<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Qt Labs China</title>
	<atom:link href="http://labs.qt.nokia.com.cn/feed/" rel="self" type="application/rss+xml" />
	<link>http://labs.qt.nokia.com.cn</link>
	<description>Qt Labs 中文</description>
	<lastBuildDate>Tue, 07 Aug 2012 09:56:32 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4.1</generator>
		<item>
		<title>Qt 5中信号和槽的新语法</title>
		<link>http://labs.qt.nokia.com.cn/2012/08/07/new-signals-slots-syntax-in-qt5/</link>
		<comments>http://labs.qt.nokia.com.cn/2012/08/07/new-signals-slots-syntax-in-qt5/#comments</comments>
		<pubDate>Tue, 07 Aug 2012 08:48:26 +0000</pubDate>
		<dc:creator>Cheng Liang</dc:creator>
				<category><![CDATA[qtearth-blogs-chinese]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://labs.qt.nokia.com.cn/?p=1047</guid>
		<description><![CDATA[参考原文：woboq: Olivier Goffart &#8211; Signals and Slots in Qt5 Qt 5 Alpha已经发布。我曾经工作过的一个新特性就是信号和槽的新语法。本篇博客将会为您讲解这一内容。 Qt 5之前的语法 这里是我们如何把信号和槽连接起来的方法： connect(sender, SIGNAL(valueChanged(QString, QString)), receiver, SLOT(updateValue(QString))); 幕后的实际情况是SIGNAL和SLOT这两个宏会把它们的参数转换成字符串。然后QObject::connect()将会把这些字符串和moc工具所收集的内省(introspection)数据进行比较。 Qt 5之前信号和槽语法的问题 虽然通常情况下都可以正常工作，我们还是发现了如下问题： 没有编译期检查：因为函数名被处理成字符串，所有的检查都是在运行时完成的。这就是为什么有时会发生编译通过了，但槽并没有被调用。此时，你就应该去检查标准输出，看看有没有什么警告说明这个连接没有成功。 因为处理的是字符串，所以槽函数中的类型名字必须与信号的完全一致，而且在头文件中的和实际的connect()语句中的也必须一致。也就是说，如果你使用了typedef或者命名空间，那么这个连接就不能正常工作。 新语法：使用函数指针 在即将到来的Qt 5中提供了一套新的语法。之前的语法依然可以使用，但是现在，我们有了全新的方式： connect(sender, &#38;Sender::valueChanged, receiver, &#38;Receiver::updateValue); 哪一种方式更酷可能取决于个人喜好。但大家会更快的适应新方式。 现在让我们先远离美学视角，来看看新语法有什么好处： 编译期检查 如果信号或者槽的名字的拼写发生了错误，或者槽函数的参数与信号的不一致，你会在编译期就得到一个错误。 这肯定会在重构、或者修改信号或槽函数的名字时节省很多时间。 另一个好处是，如果我们少了Q&#95;OBJECT宏，可以利用static&#95;cast返回更友好的错误信息。 参数的自动类型转换 现在，我们不仅可以更好地使用typedef或者命名空间，而且可以利用隐式类型转换。 在下面的例子中，我们的信号有一个QString参数，而槽函数需要的是QVariant。它可以正常工作，是因为QVariant有一个可以使用QString的隐式构造函数。 class Test : public QObject { Q_OBJECT public: Test() { connect(this, &#38;Test::someSignal, this, [...]]]></description>
			<content:encoded><![CDATA[<p>参考原文：<a href="http://woboq.com/blog/">woboq: Olivier Goffart</a> &#8211; <a href="http://woboq.com/blog/new-signals-slots-syntax-in-qt5.html">Signals and Slots in Qt5</a></p>

<p>Qt 5 Alpha已经发布。我曾经工作过的一个新特性就是信号和槽的<a href="http://qt-project.org/wiki/New_Signal_Slot_Syntax">新语法</a>。本篇博客将会为您讲解这一内容。</p>

<p><span id="more-1047"></span>
<h1>Qt 5之前的语法</h1></p>

<p>这里是我们如何把信号和槽连接起来的方法：</p>

<pre class="brush:cpp">connect(sender, SIGNAL(valueChanged(QString, QString)),
        receiver, SLOT(updateValue(QString)));</pre>

<p>幕后的实际情况是<code>SIGNAL</code>和<code>SLOT</code>这两个宏会把它们的参数转换成字符串。然后<code>QObject::connect()</code>将会把这些字符串和<code>moc</code>工具所收集的内省(introspection)数据进行比较。</p>

<h1>Qt 5之前信号和槽语法的问题</h1>

<p>虽然通常情况下都可以正常工作，我们还是发现了如下问题：</p>

<ul>
    <li>没有编译期检查：因为函数名被处理成字符串，所有的检查都是在运行时完成的。这就是为什么有时会发生编译通过了，但槽并没有被调用。此时，你就应该去检查标准输出，看看有没有什么警告说明这个连接没有成功。</li>
    <li>因为处理的是字符串，所以槽函数中的类型名字必须与信号的完全一致，而且在头文件中的和实际的<code>connect()</code>语句中的也必须一致。也就是说，如果你使用了<code>typedef</code>或者命名空间，那么这个连接就不能正常工作。</li>
</ul>

<h1>新语法：使用函数指针</h1>

<p>在即将到来的Qt 5中提供了一套新的语法。之前的语法依然可以使用，但是现在，我们有了全新的方式：</p>

<pre class="brush:cpp">connect(sender, &amp;Sender::valueChanged,
        receiver, &amp;Receiver::updateValue);</pre>

<p>哪一种方式更酷可能取决于个人喜好。但大家会更快的适应新方式。</p>

<p>现在让我们先远离美学视角，来看看新语法有什么好处：</p>

<h2>编译期检查</h2>

<p>如果信号或者槽的名字的拼写发生了错误，或者槽函数的参数与信号的不一致，你会在编译期就得到一个错误。</p>

<p>这肯定会在重构、或者修改信号或槽函数的名字时节省很多时间。</p>

<p>另一个好处是，如果我们少了<code>Q&#95;OBJECT</code>宏，可以利用<code>static&#95;cast</code>返回更友好的错误信息。</p>

<h2>参数的自动类型转换</h2>

<p>现在，我们不仅可以更好地使用<code>typedef</code>或者命名空间，而且可以利用隐式类型转换。</p>

<p>在下面的例子中，我们的信号有一个<code>QString</code>参数，而槽函数需要的是<code>QVariant</code>。它可以正常工作，是因为<code>QVariant</code>有一个可以使用<code>QString</code>的隐式构造函数。</p>

<pre class="brush:cpp">class Test : public QObject
{
    Q_OBJECT
public:
    Test() {
        connect(this, &amp;Test::someSignal, this, &amp;Test::someSlot);
    }
signals:
    void someSignal(const QString &amp;);
public:
    void someSlot(const QVariant &amp;);
};</pre>

<h2>连接到任意函数</h2>

<p>如果你留心上面的例子，就会发现，我们的信号被连接到了一个槽，但是它的声明只有<code>public</code>，没有<code>slot</code>。Qt的新语法通过函数指针直接调用函数，而不再需要<code>moc</code>的内省（但是信号依然需要）。</p>

<p>更进一步，我们可以将信号连接到任意函数或者函数对象(functor)：</p>

<pre class="brush:cpp">static void someFunction() {
    qDebug() &lt;&lt; "pressed";
}

// ... 然后其它地方
QObject::connect(button, &amp;QPushButton::clicked, someFunction);</pre>

<p>这样处理，就可以让你很方便的同<code>boost</code>或者<code>tr1::bind</code>进行协作。</p>

<h2>C++11 Lambda表达式</h2>

<p>至此之前，我们所有的示例都是基于<code>C++98</code>标准的。但是，如果你的编译器支持<code>C++11</code>，我还是强烈建议你使用一些这个语言的新特性。现在，<code>Lambda</code>表达式至少被<code>MSVC 2010</code>、<code>GCC 4.5</code>、<code>clang 3.1</code>这几个编译器支持。不过对于后面两个编译器，你需要在编译时加上<code>-std=c++0x</code>参数。</p>

<p>然后我们就可以这样写代码了：</p>

<pre class="brush:cpp">void MyWindow::saveDocumentAs() {
    QFileDialog *dlg = new QFileDialog();
    dlg-&gt;open();
    QObject::connect(dlg, &amp;QDialog::finished, [=](int result) {
        if (result) {
            QFile file(dlg-&gt;selectedFiles().first());
            // ... 在这里保存文档 ...
        }
        dlg-&gt;deleteLater();
    });
}</pre>

<p>这种语法允许我们更方便地编写异步代码。</p>

<p>更新：您还可以看看<a href="http://labs.qt.nokia.com.cn/2012/07/09/cpp11-in-qt/">Qt 5中提供的其它C++11特性</a>。</p>

<h1>现在该干什么呢？</h1>

<p>让我们来尝试一下吧。<a href="http://labs.qt.nokia.com.cn/2012/04/16/qt-5-alpha/">下载Qt 5 Alpha</a>，开始玩吧。不要忘记报告Bug呀。</p>

<p>（译者注：感谢<a href="http://labs.qt.nokia.com.cn/author/liangqi/">齐亮</a>对本篇博客全文进行了修正。）</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qt.nokia.com.cn/2012/08/07/new-signals-slots-syntax-in-qt5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Qt 5 Accessibility APIs</title>
		<link>http://labs.qt.nokia.com.cn/2012/07/13/qt-5-accessibility-apis/</link>
		<comments>http://labs.qt.nokia.com.cn/2012/07/13/qt-5-accessibility-apis/#comments</comments>
		<pubDate>Fri, 13 Jul 2012 11:35:30 +0000</pubDate>
		<dc:creator>Bai Jing</dc:creator>
				<category><![CDATA[Qt]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[accessibility]]></category>
		<category><![CDATA[qt 5]]></category>

		<guid isPermaLink="false">http://labs.qt.nokia.com.cn/?p=1038</guid>
		<description><![CDATA[原文地址：Frederik Gladhorn &#8211; Qt 5 Accessibility APIs Qt 5是一个Qt 4的渐进而平缓的升级版。 除了一些我们认为绝对必要的情况以外基本没有打破源码兼容性。其中一个我们决定作出重大改变并影响人们移植到Qt 5的是Accessibility。 （而作出改变的）原因是我们被老API的状态束缚了手脚，无法改进Qt的accessibility在所有平台上的实现使之适应现代需要。 目前我们把所有的accessibility的API标记为内部使用。 意味着它们是“隐藏”的，不会出现在文档中。 这是因为经过我们的大幅修改，不确信新的API测试已经充分。 我们认为Qt 5.1发布将是正确的时机， 但所有的支持都已就位， 任何想要尝试的人都可以直接进行， 不需要特殊的设置。 也就是说即使目前尚无文档，你仍然可以预期这部分已经比Qt 4更好地工作。 在新的Linux accessibility bridge上所做的工作， 我们在用户提供的反馈帮助下发现了很多不足，现在我们正在尽可能解决。原始API以Windows 95支持的MSSA为灵感。不用想也猜得到，既然世界不断前进，很多帮助开发者更好地支持用户并让用户更好地使用他们的电脑的技术出现了。但我们并没有做任何革命性的改变，很多细节被润色， API更清晰不易出错。 一个重大的改进是通知发送给平台的方式， 终于可以为工具提供足够的信息。 Qt 5 在经历了小退一步之后， 我们改进了Mac, Window和Linux平台的集成。 这将是第一个提供所有桌面平台、好的accessibility特性的Qt版本。 除了传统的QWidget世界，我们还扩大了向QML的努力。 仍然有一些未解决的问题， 但当前系统实际上已经过广泛测试， 例如在广受使用Ubuntu的屏幕阅读器的用户喜爱的软件Unity-2d中显示，QML和accessibility可以齐头并进。 在Mac平台上我们终于提供了基于Cocoa的后端，代替古老的Carbon后端。 这个桥（连接Qt的Accessibility API和Mac的API）仍然新鲜稚嫩，需要你们帮助测试和润色。现在Windows的accessibility桥在MSAA之后支持 IAccessible 2， 应该能为屏幕阅读器提供众多元素－－诸如表格、列表－－更好的支持。在Linux平台上新的qt-at-spi桥在Qt 4经过测试， 能和Gnome和KDE工作。 Qt 5的这部分经过很大的改进， 将作为插件集成为Qt的一部分， 随Qt 5.0或Qt 5.1发布。 [...]]]></description>
			<content:encoded><![CDATA[<p>原文地址：<a href="http://labs.qt.nokia.com/author/frederik/" rel="nofollow">Frederik Gladhorn</a> &#8211; <a title="Qt 5 Accessibility APIs" href="http://labs.qt.nokia.com/2012/06/18/qt-5-accessibility-apis/">Qt 5 Accessibility APIs</a></p>

<p>Qt 5是一个Qt 4的渐进而平缓的升级版。 除了一些我们认为绝对必要的情况以外基本没有打破源码兼容性。其中一个我们决定作出重大改变并影响人们移植到Qt 5的是Accessibility。 （而作出改变的）原因是我们被老API的状态束缚了手脚，无法改进Qt的accessibility在所有平台上的实现使之适应现代需要。</p>

<p>目前我们把所有的accessibility的API标记为内部使用。 意味着它们是“隐藏”的，不会出现在文档中。 这是因为经过我们的大幅修改，不确信新的API测试已经充分。 我们认为Qt 5.1发布将是正确的时机， 但所有的支持都已就位， 任何想要尝试的人都可以直接进行， 不需要特殊的设置。 也就是说即使目前尚无文档，你仍然可以预期这部分已经比Qt 4更好地工作。</p>

<p>在新的Linux accessibility bridge上所做的工作， 我们在用户提供的反馈帮助下发现了很多不足，现在我们正在尽可能解决。原始API以Windows 95支持的MSSA为灵感。不用想也猜得到，既然世界不断前进，很多帮助开发者更好地支持用户并让用户更好地使用他们的电脑的技术出现了。但我们并没有做任何革命性的改变，很多细节被润色， API更清晰不易出错。 一个重大的改进是通知发送给平台的方式， 终于可以为工具提供足够的信息。
Qt 5 在经历了小退一步之后， 我们改进了Mac, Window和Linux平台的集成。 这将是第一个提供所有桌面平台、好的accessibility特性的Qt版本。 除了传统的QWidget世界，我们还扩大了向QML的努力。 仍然有一些未解决的问题， 但当前系统实际上已经过广泛测试， 例如在广受使用Ubuntu的屏幕阅读器的用户喜爱的软件Unity-2d中显示，QML和accessibility可以齐头并进。</p>

<p>在Mac平台上我们终于提供了基于Cocoa的后端，代替古老的Carbon后端。 这个桥（连接Qt的Accessibility API和Mac的API）仍然新鲜稚嫩，需要你们帮助测试和润色。现在Windows的accessibility桥在MSAA之后支持 IAccessible 2， 应该能为屏幕阅读器提供众多元素－－诸如表格、列表－－更好的支持。在Linux平台上新的qt-at-spi桥在Qt 4经过测试， 能和Gnome和KDE工作。 Qt 5的这部分经过很大的改进， 将作为插件集成为Qt的一部分， 随Qt 5.0或Qt 5.1发布。</p>

<p>应用程序开发者应能获得在所有平台上的更多的accessibility特性，更好的可直接使用的屏幕阅读器。 但可以预料的是这个功能并不完美， 所以请给我们反馈意见。 如果你曾实现支持更多的accessibility功能，而且你的窗体派生了QAccessibleInterface，我们将特别希望收到你的反馈。 文档都在代码中， 请尽情阅读.cpp文件中的解释类的改进的注释。</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qt.nokia.com.cn/2012/07/13/qt-5-accessibility-apis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Qt 5中元对象系统的改变</title>
		<link>http://labs.qt.nokia.com.cn/2012/07/11/changes-to-the-meta-object-system-in-qt-5/</link>
		<comments>http://labs.qt.nokia.com.cn/2012/07/11/changes-to-the-meta-object-system-in-qt-5/#comments</comments>
		<pubDate>Wed, 11 Jul 2012 07:12:40 +0000</pubDate>
		<dc:creator>Cheng Liang</dc:creator>
				<category><![CDATA[qt-blogs-chinese]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://labs.qt.nokia.com.cn/?p=981</guid>
		<description><![CDATA[原文地址：Kent Hansen &#8211; Changes to the Meta-Object System in Qt 5 Qt 5的元对象系统作出了一些改变，既有底层变化，又有API的变化。其中有些修改与Qt 4不是源代码兼容的。本文将介绍这些改变，以及如何修改现有代码，使其能够使用Qt 5进行编译。同时，我们也将阐述下新增加的一些 API，使QMetaMethod更方便使用。 移除Qt 4元对象版本的支持 元对象数据（例如由moc生成的）有一个版本号，用于描述元对象的内容（格式/布局）和特性。当我们向新的主要版本的Qt的元对象增加新特性时（例如让一个类的构造函数支持内省(introspect)），我们必须更新这个元数据版本号。Qt 4最终一代元对象版本是6。 为了保持向后兼容，新的小版本的Qt更新必须支持早期版本的元对象。这是由Qt内部在恰当位置检查元对象版本来实现的。如果元对象是旧的，那么就要切换到早期版本的代码。 因为 Qt 5已经不与Qt 4二进制兼容，因此，我们选择不支持旧的元对象系统了。也就是说，前面我们说的保持旧有代码在Qt 5中已经没有了，因为Qt不再使用Qt 4所使用的那个版本的元对象了。Qt 5的元对象版本号是7。 Qt 4的moc输出代码也不能使用Qt 5编译。如果你的代码中有手工修改的moc输出代码（希望没有，不过Qt自己倒是使用了一些，用于实现“特殊的”元对象），你必须自己修改这些代码。 Qt的很多运行时的元对象构建器（QMetaObjectBuilder、QtDBus、ActiveQt等）也必须修改代码，以便兼容第7版元对象。不过，因为这些代码通常是内部使用的，因此不会影响到使用这些库的程序。（希望没人自己编写了一个元对象构建器…） 函数不再使用字符串识别 在Qt 5之前的版本，元对象包含了类信号、槽以及Q&#95;INVOKABLE函数的完整的一般化签名，将其逐字存储为以&#8217;0&#8242;为终止符的字符串。这在对于完全基于字符串的QObject::connect()是必须的（使用SIGNAL()和SLOT()宏）。但是现在QObject::connect()是基于模板的，将函数的完整签名作为字符串存储就不那么明智了。（QObject::connectNotify()函数造成Qt4内部不得不处理签名字符串，我们会在后文详细说明。） 函数内省(introspect)的另外一个常见用例是动态绑定（QML、QScript）。在这种情况下，一个字符串的签名就不那么合适。如果能够直接访问函数名和参数类型，由于减少了运行时解析字符串，会更为简单和有效。 注意，Qt 5中，QMetaMethod有了新的函数：name()、parameterCount()和parameterType(int index)。完整的函数签名已经不在元对象数据中存储了（只有函数名），因为正确的签名可以从上面所说的各个函数返回的信息拼接出来。 现在的QMetaMethod::signature()函数返回一个const char *，这不幸地泄露了签名曾被逐字存储。我们不能简单地将返回类型修改成QByteArray，因为类似如下代码的隐式类型转换将会使程序崩溃，但是却不会有任何警告： // 如果 signature() 返回 QByteArray，在下面语句执行过后，返回值将会超出作用域（也就会被销毁） const char *sig = someMethod.signature(); // 试试看使用sig做些处理吧！ 为了解决这个问题，我们在Qt [...]]]></description>
			<content:encoded><![CDATA[<p>原文地址：<a href="http://labs.qt.nokia.com/author/kent/">Kent Hansen</a> &#8211; <a href="http://labs.qt.nokia.com/2012/06/22/changes-to-the-meta-object-system-in-qt-5/">Changes to the Meta-Object System in Qt 5</a></p>

<p>Qt 5的元对象系统作出了一些改变，既有底层变化，又有API的变化。其中有些修改与Qt 4不是源代码兼容的。本文将介绍这些改变，以及如何修改现有代码，使其能够使用Qt 5进行编译。同时，我们也将阐述下新增加的一些 API，使QMetaMethod更方便使用。</p>

<p><span id="more-981"></span>
<h1>移除Qt 4元对象版本的支持</h1>
元对象数据（例如由<a href="http://doc-snapshot.qt-project.org/5.0/moc.html">moc</a>生成的）有一个版本号，用于描述元对象的内容（格式/布局）和特性。当我们向新的主要版本的Qt的元对象增加新特性时（例如让一个类的构造函数支持内省(introspect)），我们必须更新这个元数据版本号。Qt 4最终一代元对象版本是6。</p>

<p>为了保持向后兼容，新的小版本的Qt更新必须支持早期版本的元对象。这是由Qt内部在恰当位置检查元对象版本来实现的。如果元对象是旧的，那么就要切换到早期版本的代码。</p>

<p>因为 Qt 5已经不与Qt 4二进制兼容，因此，我们选择不支持旧的元对象系统了。也就是说，前面我们说的保持旧有代码在Qt 5中已经没有了，因为Qt不再使用Qt 4所使用的那个版本的元对象了。Qt 5的元对象版本号是7。</p>

<p><strong>Qt 4的moc输出代码也不能使用Qt 5编译</strong>。如果你的代码中有手工修改的moc输出代码（希望没有，不过Qt自己倒是使用了一些，用于实现“特殊的”元对象），你必须自己修改这些代码。</p>

<p>Qt的很多运行时的元对象构建器（QMetaObjectBuilder、QtDBus、ActiveQt等）也必须修改代码，以便兼容第7版元对象。不过，因为这些代码通常是内部使用的，因此不会影响到使用这些库的程序。（希望没人自己编写了一个元对象构建器…）
<h1>函数不再使用字符串识别</h1>
在Qt 5之前的版本，元对象包含了类信号、槽以及Q&#95;INVOKABLE函数的完整的<a href="http://doc-snapshot.qt-project.org/5.0/qmetaobject.html#normalizedSignature">一般化签名</a>，将其逐字存储为以&#8217;0&#8242;为终止符的字符串。这在对于完全基于字符串的QObject::connect()是必须的（使用SIGNAL()和SLOT()宏）。但是现在<a href="http://doc-snapshot.qt-project.org/5.0/qobject.html#connect-4">QObject::connect()是基于模板的</a>，将函数的完整签名作为字符串存储就不那么明智了。（QObject::connectNotify()函数造成Qt4内部不得不处理签名字符串，我们会在后文详细说明。）</p>

<p>函数内省(introspect)的另外一个常见用例是动态绑定（QML、QScript）。在这种情况下，一个字符串的签名就不那么合适。如果能够直接访问函数名和参数类型，由于减少了运行时解析字符串，会更为简单和有效。</p>

<p>注意，Qt 5中，<a href="http://doc-snapshot.qt-project.org/5.0/qmetamethod.html">QMetaMethod</a>有了新的函数：name()、parameterCount()和parameterType(int index)。完整的函数签名已经不在元对象数据中存储了（只有函数名），因为正确的签名可以从上面所说的各个函数返回的信息拼接出来。</p>

<p>现在的<a href="http://qt-project.org/doc/qt-4.8/qmetamethod.html#signature">QMetaMethod::signature()</a>函数返回一个const char *，这不幸地泄露了签名曾被逐字存储。我们不能简单地将返回类型修改成QByteArray，因为类似如下代码的隐式类型转换将会使程序崩溃，但是却不会有任何警告：
<pre class="brush:cpp">// 如果 signature() 返回 QByteArray，在下面语句执行过后，返回值将会超出作用域（也就会被销毁）
const char *sig = someMethod.signature();
// 试试看使用sig做些处理吧！</pre>
为了解决这个问题，我们在Qt 5引入一个新函数，<a href="http://doc-snapshot.qt-project.org/5.0/qmetamethod.html#methodSignature">QMetaMethod::methodSignature()</a>。<strong>不再提供</strong><strong>老函数QMetaMethod::signature()，调用此函数将触发编译错误，提示该函数被更名。</strong>现有代码应该修改成使用QMetaMethod::methodSignature()。即使有了诸如QMetaMethod::name()的新函数，在某些情况下仍然需要获取完整的签名，比如在调试的时候。
<h1>connectNotify()和disconnectNotify()</h1>
<a href="http://doc-snapshot.qt-project.org/5.0/qobject.html#connectNotify">QObject::connectNotify()</a>和disconnectNotify()是两个很少被重写的虚函数。这两个函数适用在别人连接到你的信号或断开连接的时候。一个潜在的使用情景是，实现隐藏代理(lazy proxy)的时候，将一个内部对象（后端）连接到一个公有的信号上面。例如qtsystems模块就大量使用了这一特性。</p>

<p>在Qt 5之前，connectNotify()为了配合基于字符串的QObject::connect()函数，其参数是const char指针，指向标识所连接的信号的一般化签名，用于识别连接到的是哪一个信号。对于基于模板的QObject::connect()以及诸如QML 或QtScript中使用的自定义的连接，只为了调用一个通常没有被重写的虚函数，就让Qt准备一个以字符串形式表达的信号， 十分不明智。</p>

<p>另外，基于字符指针的connectNotify()不是Qt的风格。即便你能够拼写正确每一个函数签名，你也有可能陷入下面的陷阱（这样的问题代码甚至出现在Qt内部）：
<pre class="brush:cpp">void MyClass::connectNotify(const char *signal)
{
    if (signal == SIGNAL(mySignal())) {
        // 这永远不会执行，因为比较的是指针而不是字符串内容</pre>
文档说，你应该将signal参数包装成QLatin1String，但经常会忘记这么做。Qt 5的解决方案是不允许出现这样的错误。</p>

<p><strong>在Qt 5中，QObject::connectNotify()和disconnectNotify()接受一个QMetaMethod，而不是字符指针</strong>。QMetaMethod仅仅是QMetaObject指针和一个索引的轻量级封装。这样就不会被建立连接的方式所左右。</p>

<p>这种变化同时允许我们将对connectNotify()和disconnectNotify()的调用转移到内部基于索引的connect()和disconnect()函数(QMetaObject::connect()，该函数在Qt内部有好几处使用)的实现中。在实际应用中，这意味着即使QObject::connect()没有显式调用（例如<a href="http://doc-snapshot.qt-project.org/5.0/qmetaobject.html#connectSlotsByName">connectSlotsByName()</a>）你重新实现的connectNotify()函数也会按预期被调用。最后，我们可以丢弃掉某些Qt里的蹩脚的代码，例如那些手工调用的connectNotify(const char *)，转而使用基于索引的connect()。</p>

<p>已经重写了connectNotify()和disconnectNotify()的现有代码需要迁移到新的API。有两个函数会让这个工作变得简单：QMetaMethod::fromSignal()和QObject::isSignalConnected()。
<h1>QMetaMethod::fromSignal()</h1>
新的静态函数<a href="http://doc-snapshot.qt-project.org/5.0/qmetamethod.html#fromSignal">QMetaMethod::fromSignal()</a>将一个成员函数（一个信号）作为参数，返回对应的QMetaMethod。它可以很方便地用于新的connectNotify()：
<pre class="brush:cpp">void MyClass::connectNotify(const QMetaMethod &amp;signal)
{
    if (signal == QMetaMethod::fromSignal(&amp;MyClass::mySignal)) {
        // 连接到mySignal ...</pre>
为了避免每次调用connectNotify()的时候都要重新查找一个信号，应该将QMetaMethod::fromSignal()的返回值作为一个静态变量存储起来。</p>

<p>另外fromSignal()的一个鲜为人知的用法是用于排队发射信号（queued emission）（QMetaObject::invokeMethod()也可以实现相同的功能，但它是基于字符串的）：
<pre class="brush:cpp">QMetaMethod::fromSignal(&amp;MyClass::mySignal)
    .invoke(myObject, Qt::QueuedConnection /* 其他参数 ... */);</pre>
<h1>QObject::isSignalConnected()</h1>
新的函数<a href="http://doc-snapshot.qt-project.org/5.0/qobject.html#isSignalConnected">QObject::isSignalConnected()</a>用于检查一个信号是否有槽与之连接。这是一个基于QMetaMethod的，用于替代QObject::receivers()的函数。
<pre class="brush:cpp">void MyClass::disconnectNotify(const QMetaMethod &amp;signal)
{
    if (signal == QMetaMethod::fromSignal(&amp;MyClass::mySignal)) {
        // 有槽从mySignal断开连接
        if (!isSignalConnected(signal)) {
            // 该信号没有连接，我们可以释放其资源 ...</pre>
另外，你可以使用这个函数避免将许多信号一同发射，例如，如果信号的发射将引起可能严重影响程序性能的复杂计算。
<h1><a href="https://bugreports.qt-project.org/browse/QTBUG-4844"><del datetime="2012-06-29T07:14:06+00:00">QTBUG-4844</del></a>: 接收者被销毁时QObject::disconnectNotify()未调用</h1>
<strong>更新</strong>：<a href="https://codereview.qt-project.org/#change,29423">https://codereview.qt-project.org/#change,29423</a>已经修正这个问题</p>

<p><del datetime="2012-06-29T07:14:06+00:00">这个bug现在依然存在</del>。这是造成disconnectNotify()“不完整”（或“不工作”，取决于你如何看待）的缺陷，所以我很希望该问题被修正。</p>

<p>为了能有效地实现所期望的行为，连接需要记住信号的id。因为当接收者被销毁时，我们无法像通常在（显式）断开连接时那样再获取信号id。这将给所有的连接都增加额外字节支出（一个int的大小）。如果你有更聪明的解决方案，现在仍然有提交到Qt 5的时间（这个修改是个行为的改变，对于未来的小版本发布来说未免太大）。
<h1>函数返回类型</h1>
在Qt 5之前的版本中，我们必须使用<a href="http://doc-snapshot.qt-project.org/5.0/qmetamethod.html#typeName">QMetaMethod::typeName()</a>判断一个函数的返回值类型，其格式是const char指针。诡异的是，如果返回值是void，typeName()返回空字符串，而不是像QMetaType::typeName()那样返回字符串“void”。这种不一致让人迷惑不解，例如我曾看到代码：
<pre class="brush:cpp">if (!method.typeName() || !*method.typeName() || !strcmp(method.typeName(), "void")){
    // 返回值是 void ...</pre>
&#8230;为了确认，必须这么判断。</p>

<p>在Qt 5中，我们可以使用新函数<a href="http://doc-snapshot.qt-project.org/5.0/qmetamethod.html#returnType">QMetaMethod::returnType()</a>，其返回值是一个<a href="http://doc-snapshot.qt-project.org/5.0/qmetatype.html">meta-type</a> id：
<pre class="brush:cpp">if (method.returnType() == QMetaType::Void) {
    // 返回值是 void ...</pre>
Qt 4中你无法使用QMetaType::Void区分void和未注册类型（它们都是整型0）。Qt 5中的QMetaType::Void就是void，新的QMetaType::UnknownType则用于指定一个未注册到Qt类型系统中的类型。</p>

<p>（备注：如果你的现有代码将类型id与QMetaType::Void（或者整型0）进行比较，那么我的建议是，在切换到Qt 5的时候再次检查你的逻辑：是应该检查是不是void，未知类型，还是两个都要？）</p>

<p><strong>为了与QMetaType保持一致，当返回值类型是void的时候，Qt 5的QMetaMethod::typeName()返回字符串“void”</strong>。现有的用typeName()返回空字符串代表void的代码必须要修改（将returnType()与QMetaType::Void进行比较）。
<h1>函数参数</h1>
类似QMetaMethod::returnType()，新的<a href="http://doc-snapshot.qt-project.org/5.0/qmetamethod.html#parameterType">QMetaMethod::parameterType()</a>函数返回参数类型的meta-type id。QMetaMethod::parameterCount()返回参数个数。使用这两个函数就可以替代旧的QMetaMethod::parameterTypes()，后者以字符串的形式返回所有参数类型（名字）。</p>

<p>如果在元对象定义时（如调用moc时），类型已知（内建类型），类型id会直接嵌入到元对象数据中， 查找将非常迅速。对于其他类型，id的解析则会是基于字符串的查找，这也并不会比之前慢（还可以通过缓存解析结果进行优化）。
<h1>结论</h1>
Qt 5的元对象系统（元类型系统也是如此，但细节留到下一篇博文）有了一些小的变化。函数现在有更恰当更易于维护的语义，而不是普通的C字符串。与Qt 4源代码兼容最大程度的保持着（如果兼容性没有破坏，请不要修改——但有些Qt 4的错误我们不得不解决）。我们清除了实现代码中的遗留问题。 一些Qt模块已经使用了新特性，从而获得更清晰、快速的代码。希望那些对于元对象系统持批评态度的人可以偃旗息鼓了。</p>

<p>（译者注：感谢<a href="http://labs.qt.nokia.com.cn/author/baijing/">Bai Jing</a>对本篇博客全文进行了修正。）</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qt.nokia.com.cn/2012/07/11/changes-to-the-meta-object-system-in-qt-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++ 11在Qt 5中的应用</title>
		<link>http://labs.qt.nokia.com.cn/2012/07/09/cpp11-in-qt/</link>
		<comments>http://labs.qt.nokia.com.cn/2012/07/09/cpp11-in-qt/#comments</comments>
		<pubDate>Mon, 09 Jul 2012 09:38:44 +0000</pubDate>
		<dc:creator>Cheng Liang</dc:creator>
				<category><![CDATA[qtearth-blogs-chinese]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[Qt5]]></category>

		<guid isPermaLink="false">http://labs.qt.nokia.com.cn/?p=979</guid>
		<description><![CDATA[参考原文：woboq: Olivier Goffart &#8211; C++11 in Qt5 C++ 11现在已经是C++标准，也就没有理由不在新的应用中使用。 Qt 4.8是第一个支持C++ 11特性的Qt版本。我在4.8发布之前写过一篇博客——Qt中的C++0x，这里就不再重复了。 显而易见的是，比起Qt 4.8，Qt 5利用了更多的C++ 11新特性。下面我们来一个个见识一下： 槽中使用Lambda表达式 Lambda表达式是C++ 11带来的最激动人心的特性之一。简而言之，它允许创建匿名函数。匿名函数则允许我们直接将一个函数作为参数传递，无需显式地声明。 在此之前，使用利用operator()在结构体中实现仿函数需要很多技巧性代码。 Qt 4.8实际已经可以使用这个特性。只不过在Qt 4.8中，Lambda表达式只能用在QtConcurrent的某些函数。现在，前面我们也介绍过，Qt 5有Qt 5中新的信号/槽语法，Lambda表达式有了更大的用武之地。回忆一下，在你需要编写槽代码的时候，即使只有一条语句，你也必须为它单独建立一个函数。这不是很麻烦吗？现在，我们有了更好的写法： connect(sender, &#38;Sender::valueChanged, [=](const QString &#38;newValue) { receiver-&#62;updateValue("senderValue", newValue); }); Lambda表达式现在已经被MSVC 2010、GCC 4.5和clang 3.1实现。 Unicode字符串常量 C++ 11允许你使用u"HelloWorld"的形式生成UTF-16字符串。Qt利用这个特性增加了一个新的类QStringLiteral。这个类能够在编译时初始化QString，没有了运行时的时间消耗。参考之前关于QStringLiteral的文章。 QString str = QStringLiteral("HelloWorld"); 常量表达式 constexpr C++ 11增加了新的关键字constexpr，指示某些内联函数可以在编译期运算。在Qt 5中，我们引入了Q&#95;DECL&#95;CONSTEXPR宏，当所使用的编译期支持constexpr时，这个宏可以生成constexpr，否则的话则是空白。 在Qt源代码中，我们也利用这个宏改写了许多函数，例如： enum SomeEnum { Value1, [...]]]></description>
			<content:encoded><![CDATA[<p>参考原文：<a href="http://woboq.com/blog/">woboq: Olivier Goffart</a> &#8211; <a href="http://woboq.com/blog/cpp11-in-qt5.html">C++11 in Qt5</a></p>

<p>C++ 11现在已经是C++标准，也就没有理由不在新的应用中使用。</p>

<p>Qt 4.8是第一个支持C++ 11特性的Qt版本。我在4.8发布之前写过一篇博客——<a href="http://labs.qt.nokia.com.cn/2011/08/22/cpp0x-in-qt/">Qt中的C++0x</a>，这里就不再重复了。</p>

<p>显而易见的是，比起Qt 4.8，Qt 5利用了更多的C++ 11新特性。下面我们来一个个见识一下：</p>

<p><span id="more-979"></span>
<h2>槽中使用Lambda表达式</h2>
<a href="http://en.wikipedia.org/wiki/Anonymous_function#C.2B.2B">Lambda表达式</a>是C++ 11带来的最激动人心的特性之一。简而言之，它允许创建匿名函数。匿名函数则允许我们直接将一个函数作为参数传递，无需显式地声明。</p>

<p>在此之前，使用利用<tt>operator()</tt>在结构体中实现<a href="http://en.wikipedia.org/wiki/Function_object#In_C_and_C.2B.2B">仿函数</a>需要很多技巧性代码。</p>

<p>Qt 4.8实际已经可以使用这个特性。只不过在Qt 4.8中，Lambda表达式只能用在QtConcurrent的某些函数。现在，前面我们也介绍过，Qt 5有<a href="http://www.devbean.info/2012/04/signals-slots-in-qt5/">Qt 5中新的信号/槽语法</a>，Lambda表达式有了更大的用武之地。回忆一下，在你需要编写槽代码的时候，即使只有一条语句，你也必须为它单独建立一个函数。这不是很麻烦吗？现在，我们有了更好的写法：</p>

<pre class="brush:cpp">
connect(sender, &amp;Sender::valueChanged, [=](const QString &amp;newValue) {
    receiver-&gt;updateValue("senderValue", newValue);
});
</pre>

<p>Lambda表达式现在已经被MSVC 2010、GCC 4.5和clang 3.1实现。</p>

<h2>Unicode字符串常量</h2>

<p>C++ 11允许你使用<code>u"HelloWorld"</code>的形式生成UTF-16字符串。Qt利用这个特性增加了一个新的类<code>QStringLiteral</code>。这个类能够在编译时初始化QString，没有了运行时的时间消耗。参考之前<a href="http://woboq.com/blog/qstringliteral.html">关于QStringLiteral的文章</a>。</p>

<pre class="brush:cpp">
QString str = QStringLiteral("HelloWorld");
</pre>

<h2>常量表达式 constexpr</h2>

<p>C++ 11增加了新的关键字<tt>constexpr</tt>，指示某些内联函数可以在编译期运算。在Qt 5中，我们引入了<a href="http://qt-project.org/doc/qt-5.0/qtglobal.html#Q_DECL_CONSTEXPR">Q&#95;DECL&#95;CONSTEXPR</a>宏，当所使用的编译期支持<tt>constexpr</tt>时，这个宏可以生成<tt>constexpr</tt>，否则的话则是空白。</p>

<p>在Qt源代码中，我们也利用这个宏改写了许多函数，例如：</p>

<pre class="brush:cpp">
enum SomeEnum { Value1, Value2, Value3 };

Q_DECLARE_OPERATORS_FOR_FLAGS(QFlags&lt;SomeEnum&gt;)
// 上面一句声明了下述函数：
// Q_DECL_CONSTEXPR QFlags&lt;SomeValue&gt; operator|(SomeValue,SomeValue) {...}

int someFunction(QFlags&lt;SomeEnum&gt; value) {
    switch (value) {
        case SomeEnum::Value1:
            return 1;
        case SomeEnum::Value2:
            return 2;
        case SomeEnum::Value1 | SomeEnum::Value3:
        // 这一个 case 仅在 C++ 11 中通过编译
        // 因为 QFlags 运算符是 constexpr 的，也就是在编译期即可确定
        // 而在之前版本则必须是 
        //        QFlags&lt;SomeValue&gt; operator|(SomeValue,SomeValue)
        // 这会引发一个错误，因为 case 语句要求编译期常量
            return 3;
        default:
            return 0;
    }
}
</pre>

<p>注意，这里我们在枚举值前面使用可<code>SomeEnum::</code>前缀，这是C++ 11允许的，但是之前版本的C++则不允许。</p>

<h2>static_assert</h2>

<p>在编译期使用<tt>static&#95;assert</tt>检测问题，可以让C++ 11帮助我们可以组织处更好的错误信息。Qt 5引入了<tt>Q&#95;STATIC&#95;ASSERT</tt>和<tt>Q&#95;STATIC&#95;ASSERT&#95;X</tt>两个宏。当<tt>static&#95;assert</tt>可用时，这两个宏将使用<tt>static&#95;assert</tt>，否则使用一些模板技巧。</p>

<p>为了产生更好的编译错误信息，Qt在API不方便的地方大量使用了宏。</p>

<h2>override和final</h2>

<p>你遇到过这样的错误吗？自己定义的函数名看上去同父类的某个函数同名，但却的确有某些字母打错了，以至于并没有覆盖父类函数，从而让程序不能正确运行（或者是忘记了那函数名最后面的该死的<tt>const</tt>）？</p>

<p>现在，你可以选择在的确需要覆盖父类虚函数的地方加上<tt>Q&#95;DECL&#95;OVERRIDE</tt>。如果编译器支持的话，这个宏将展开为新增加的“override”关键字。这样的话，如果编译器支持C++ 11，那么如果是简单的字母错误，你就会得到一个错误；当你重构虚函数、却忘记修改子类时，同样会引发一个错误。</p>

<pre class="brush:cpp">
class MyModel : public QStringListModel {
    //...
protected:
     Qt::ItemFlags flags (const QModelIndex &amp; index) Q_DECL_OVERRIDE;
};
</pre>

<p>注意，上面的flags()函数实际是想覆盖父类的同名函数，但是我们忘记了一个<tt>const</tt>，就会出现类似下面的错误：</p>

<pre class="brush:cpp">
mymodel.h:15: error: `Qt::ItemFlags MyModel::flags(const QModelIndex&amp;)`
 marked override, but does not override
</pre>

<p>如果虚函数不能覆盖，Qt也提供了另外一个宏，<tt>Q&#95;DECL&#95;FINAL</tt>，这个宏展开为<tt>final</tt>。</p>

<h2>deleted成员</h2>

<p>当编译器支持<tt>deleted</tt>函数时，新增加的宏<tt>Q&#95;DECL&#95;DELETE</tt>将展开为<tt>=delete</tt>。这就允许我们能够为一些常见错误提供更好的编译器错误信息。</p>

<p>deleted函数用于显式地删除那些不允许编译器自动生成的函数（例如默认构造函数、默认拷贝运算符等）。deleted函数不能被调用，如果被使用的话，将会出现一个编译器错误。</p>

<p>我们可以将其用于<tt>Q&#95;DISABLE&#95;COPY</tt>宏。在此之前，为了实现同样的目的，我们的做法是将其声明为私有的。尽管效果相同，但是错误信息却并不友好。</p>

<h2>右值引用和移动构造函数</h2>

<p>在这里，我假定你明白什么叫做“右值引用”。如果不明白，我们会在后面的文章中详细说明。Qt 5已经在内部进行了调整，以便<a href="https://qt.gitorious.org/qt/qtbase/commit/f92fdd190d056fe929f723e3f2ce9e0c0b141cec">支持移动构造函数</a>。因此，你可以大胆的使用它们了！</p>

<h2>结论</h2>

<p>对于C++ 11，MSVC不需要任何特殊的编译参数，而GCC和Clang则需要添加<tt>-std=c++0x</tt>。</p>

<p>默认情况下，Qt 5本身会使用C++ 11编译参数进行编译（如果可能的话）。</p>

<p>如果你使用的是qmake，那么，在使用Qt 5构建的程序的<tt>.pro</tt>文件中，你需要增加这么一句：</p>

<pre class="brush:cpp">CONFIG += c++11</pre>

<p>（顺便提一句，在Qt 4中，如果你需要使用C++ 11的新特性，则应该增加gcc:CXXFLAGS += -std=c++0x。具体细节，我们会在后面的文章中说明。）</p>

<p>现在，好好利用C++ 11所带来的新特性吧！私以为，仅仅为了<tt>auto</tt>这一特性，就应该尽快使用C++ 11了！</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qt.nokia.com.cn/2012/07/09/cpp11-in-qt/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Qt 4迁移至Qt 5</title>
		<link>http://labs.qt.nokia.com.cn/2012/07/09/porting-from-qt-4-to-qt-5/</link>
		<comments>http://labs.qt.nokia.com.cn/2012/07/09/porting-from-qt-4-to-qt-5/#comments</comments>
		<pubDate>Mon, 09 Jul 2012 08:29:23 +0000</pubDate>
		<dc:creator>Cheng Liang</dc:creator>
				<category><![CDATA[qtearth-blogs-chinese]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[Qt5]]></category>

		<guid isPermaLink="false">http://labs.qt.nokia.com.cn/?p=973</guid>
		<description><![CDATA[原文地址：KDAB: Stephen Kelly &#8211; Porting from Qt 4 to Qt 5 将Qt 4代码迁移到Qt 5还是比较简单的。实际上，在Qt 5开发过程中就已经注意了与Qt 4代码保持兼容性。 与Qt 3到Qt 4的迁移不同，Qt 5的核心类库并没有做大的API的修改，只有几个新的类取代了旧的（例如，像Qt 4的QList取代了QPtrList和QValueList；itemview取代了Q3ListView；graphicsview取代了Canvas API）；同时也没有那些编译通过了，但运行时的行为却与之前的不一致的（例如，QWidget::show现在是非虚函数，绘制应该在paintEvent中进行等等）。 但是，迁移的代价也不会是零。本文总结了KDE部分代码从Qt 4迁移到Qt 5所需要注意的问题。 KDE PIM是最后一个完整迁移到Qt 4和kdelibs 4的部分。迁移到Qt 5应当更快些。 迁移之前 迁移策略中应该有这么一条：能够同时使用新版本和旧版本的Qt编译代码，也就是保持Qt 4和Qt 5的兼容性。这么做的好处是，能够保证你的代码在最小化的库上可以通过编译，让你的代码在Qt 4依然可用；也能够保证在迁移过程中，单元测试代码能够顺利运行；最后，还能够很快地区别出，哪些是本来就有的bug，哪些是由于迁移到Qt 5新引入的bug。 迁移Qt3Support 迁移代码，可以从让当前Qt 4代码“现代化”开始。 从代码迁移角度来看，Qt 5的有意义的改变是，移除了Qt3Support模块，移除了所有标记为Qt3Support的API。在大多数情况下，Qt3Support的代码在Qt 4中有一个更适合的名字。有的函数直接改名，例如QWidget::setShown改为QWidget::setVisible。部分KDE代码仍然使用了旧的函数，这种情况也发生在其它古老的第三方代码库中。 从Qt 4迁移到Qt 5，移除代码中的Qt3Support API是必要的、不可避免的。虽然理论上，我们也可以为Qt 5单独编译Qt3Support模块。 修正include 相对于Qt 4，Qt 5的一个主要的基础架构修改是，将widget从QtGui模块剥离开来，放到了全新的QtWidgets模块。这显然需要改变构建系统，同时也要求新引入一些原本不需要单独引入的头文件，因为这些头文件可能从现有QtGui模块中删除了。举个例子，Qt 5中我们需要添加#include &#60;QDrag&#62;，这在之前的Qt 4的代码是不需要的。这是因为，在Qt 4中，它已经被引入到gui/kernel/qevent.h头文件，但是Qt [...]]]></description>
			<content:encoded><![CDATA[<p>原文地址：<a href="http://www.kdab.com/category/blogs/">KDAB: Stephen Kelly</a> &#8211; <a href="http://www.kdab.com/porting-from-qt-4-to-qt-5/">Porting from Qt 4 to Qt 5</a></p>

<p>将Qt 4代码迁移到Qt 5还是比较简单的。实际上，在Qt 5开发过程中就已经注意了与Qt 4代码保持兼容性。</p>

<p>与Qt 3到Qt 4的迁移不同，Qt 5的核心类库并没有做大的API的修改，只有几个新的类取代了旧的（例如，像Qt 4的QList取代了QPtrList和QValueList；itemview取代了Q3ListView；graphicsview取代了Canvas API）；同时也没有那些编译通过了，但运行时的行为却与之前的不一致的（例如，QWidget::show现在是非虚函数，绘制应该在paintEvent中进行等等）。</p>

<p>但是，迁移的代价也不会是零。本文总结了KDE部分代码从Qt 4迁移到Qt 5所需要注意的问题。</p>

<p><img src="http://www.kdab.com/wp-content/uploads/stories/kaddressbook.png" alt="KAddressbook迁移到Qt 5和KDE Frameworks 5" /></p>

<p>KDE PIM是最后一个完整迁移到Qt 4和kdelibs 4的部分。迁移到Qt 5应当更快些。</p>

<p><span id="more-973"></span>
<h1>迁移之前</h1></p>

<p>迁移策略中应该有这么一条：能够同时使用新版本和旧版本的Qt编译代码，也就是保持Qt 4和Qt 5的兼容性。这么做的好处是，能够保证你的代码在最小化的库上可以通过编译，让你的代码在Qt 4依然可用；也能够保证在迁移过程中，单元测试代码能够顺利运行；最后，还能够很快地区别出，哪些是本来就有的bug，哪些是由于迁移到Qt 5新引入的bug。</p>

<h3>迁移Qt3Support</h3>

<p>迁移代码，可以从让当前Qt 4代码“现代化”开始。</p>

<p>从代码迁移角度来看，Qt 5的有意义的改变是，移除了Qt3Support模块，移除了所有标记为Qt3Support的API。在大多数情况下，Qt3Support的代码在Qt 4中有一个更适合的名字。有的函数直接改名，例如<strong>QWidget::setShown</strong>改为<strong>QWidget::setVisible</strong>。<a href="http://thread.gmane.org/gmane.comp.kde.cvs/1094130/focus=3018">部分KDE代码仍然使用了旧的函数</a>，这种情况也发生在其它古老的第三方代码库中。</p>

<p>从Qt 4迁移到Qt 5，移除代码中的Qt3Support API是必要的、不可避免的。虽然理论上，我们也可以为Qt 5单独编译Qt3Support模块。</p>

<h3>修正include</h3>

<p>相对于Qt 4，Qt 5的一个主要的基础架构修改是，将widget从QtGui模块剥离开来，放到了全新的QtWidgets模块。这显然需要改变构建系统，同时也要求新引入一些原本不需要单独引入的头文件，因为这些头文件可能从现有QtGui模块中删除了。举个例子，Qt 5中我们需要添加<strong>#include &lt;QDrag&gt;</strong>，这在之前的Qt 4的代码是不需要的。这是因为，在Qt 4中，它已经被引入到gui/kernel/qevent.h头文件，但是Qt 5则没有。</p>

<p>另外一个有关include的修正是，你必须将之前的QtGui模块的头文件改成QtWidgets，例如，</p>

<pre class="brush:cpp">
#include &lt;QtGui/QWidget&gt;
</pre>

<p>在Qt 5中应该写成</p>

<pre class="brush:cpp">
#include &lt;QtWidgets/QWidget&gt;
</pre>

<p>为了避免更多的修改，我的建议是，使用下面这种更具可移植性的写法（这种写法在Qt 4和Qt 5中同样适用）：</p>

<pre class="brush:cpp">
#include &lt;QWidget&gt;
</pre>

<p>我们可以编写一个简单的脚本来执行这个枯燥的操作。当然，你也可以利用IDE提供的批量替换功能。就像清理Qt3Support一样，修正include的工作也应该在真正的迁移之前完成。</p>

<h3>修正平台相关的定义</h3>

<p>许多Qt和KDE程序都会有特定平台的代码。预处理器需要使用特定的宏，而在Qt 5中，所有的Q&#95;WS&#95;&#42;都变成了Q&#95;OS&#95;&#42;。例如，在Qt 4中的代码</p>

<pre class="brush:cpp">
#ifdef Q_WS_WIN
// call windows API
#endif
</pre>

<p>在Qt 5中应该写成</p>

<pre class="brush:cpp">
#ifdef Q_OS_WIN
// call windows API
#endif
</pre>

<p>Qt 5移除了Q&#95;WS&#95;<em>宏，所以所有包含了这些宏的代码都不会通过编译。这些代码（例如，特定操作系统，而不是特定窗口系统的代码）所包围的宏都应该改成Q&#95;OS&#95;</em>。</p>

<h3>丢失Q_OBJECT宏以及清理metatype</h3>

<p>Qt 4中很容易忘记在需要的地方添加Q&#95;OBJECT宏，这会导致某些不可预见的运行时bug。这些在Qt 5中也是类似的，但是如果你通过使用Q&#95;DECLARE&#95;METATYPE宏，将一个QObject子类的指针保存到QVariant时，你会得到一个编译错误（Qt 4中也会有编译错误，但Qt 4的错误与Qt 5不同）。这是因为，QVariant现在需要保存QObject子类的指针（确切的子类，强类型指针），这是QtDeclarative、语言绑定以及严重依赖QMetaObject内省API的程序所需要的新的特性。</p>

<p>另外一个影响是，Q&#95;DECLARE&#95;METATYPE宏的参数必须是完整定义，而不能是前向声明。因此，下面的代码是不能通过编译的：</p>

<pre class="brush:cpp">
class MyType;
Q_DECLARE_METATYPE(MyType);
</pre>

<p>这个宏现在必须放到MyType完整定义的地方去（例如定义它的头文件）。另外，如果MyType继承自QObject，这个宏就可以完全删除。</p>

<h3>重构</h3>

<p>Qt 5最大的变化之一是更加注重QML（一个运行时解释语言，用于创建用户界面）和QtQuick（语言相关的API）。尽管QtWidgets依然可用，迁移到QML可能获得更好的性能和用户交互特性。</p>

<p>QML是运行时解释型的，不像C++那样具有类型安全的限制，它适合于结合使用QObject子类表达的数据模型，这种数据的属性以及其它类型信息都可以由QVariant包含。</p>

<p>如果迁移到Qt 5的目的之一是增加QML的使用量，那么，你就应该注意重构已有代码，让业务逻辑和数据模型（也就是应用程序的状态表示以及数据内容）分离。这种重构可以基于Qt 4的代码。我们甚至可以基于Qt 4提供一个正常工作的或者是试验用的QML移植，来验证我们的概念。这是Qt 4就提供了QML的原因之一，我们可以把它看成是Qt5Support。</p>

<h3>移除QWS</h3>

<p>QWS系统不再是Qt 5的一部分，它的API也已经被移除。使用了这些API的代码应该移植到新的QPA系统，这是Qt 5的核心部分之一。QPA实际上在Qt 4.8就已经引入（Qt 5的API可能有些许不同）。</p>

<p>所以说，现在也可以将代码直接迁移到Qt 4的QPA，当然，以后我们还得再迁移到Qt 5，但是整体思路并不会发生重大改变。关键在于，现在没有什么有关Qt 4.8的QPA文档，只能比较Qt 5的文档做相应的处理。</p>

<h1>迁移</h1>

<p>如果你已经按照前面的步骤来到了这一步，那么就意味着你的代码可以完全兼容Qt 4，也可以把眼光放到Qt 5上。一些API在Qt 5中不是源代码兼容的，这些大部分在<a href="http://qt.gitorious.org/qt/qtbase/blobs/master/dist/changes-5.0.0">变更日志</a>中可以找到。大多数情况下，对于“通常的”代码，这些都不是问题，因为这些修改的部分很少用到，或者是仅在边缘条件下有所改变。</p>

<p>不管如何，这些改变都需要在迁移中进行处理。它们构成了Qt 4和Qt 5实际的区别，它们会强迫你放弃对Qt 4的支持，或者是使用#ifdef预处理宏来兼容其它版本。</p>

<h3>插件加载</h3>

<p>另外一个迁移问题是，在大量使用插件的系统中，插件部分的用户代码需要改变。Qt 5中，moc用于负责生产插件元数据，所以，不同于Qt 4中仅仅需要在C++文件中添加一个预处理宏Q&#95;EXPORT&#95;PLUGIN2，Qt 5需要在头文件中添加一个新的宏，以便moc能够处理。</p>

<p>这个过程还是比较直观的。但是，问题在于，如果Q&#95;EXPORT&#95;PLUGIN2宏被包裹在另外一个宏中，类似KDE的K&#95;EXPORT&#95;PLUGIN，那么这种处理就必须修改，因为Qt 5的moc不能处理这种宏的嵌套（moc不做完整的预处理）。</p>

<h3>迁移单元测试</h3>

<p>前面我们提到，有些代码不是源代码兼容的，这其中就包括QTestLib模块——对于QSKIP宏的改变。Qt 4中，这个宏有两个参数，但是在Qt 5则只有一个。</p>

<p>这造成了一个明显的迁移问题。KDE对此的解决方案是，<a href="http://permalink.gmane.org/gmane.comp.kde.devel.frameworks/313">创建一个包装宏</a>，接受两个参数，而对于Qt 5则舍弃一个。这应该是在未来需要放弃的，因为我们的程序不应该在将来还对Qt 4作一定的支持。也许这个“未来”会相当的遥远。</p>

<p>另外一个解决方案是，使用C99和C++ 11。如果你使用了-std=c++11进行编译，那么就不会有这个问题。</p>

<h3>QMetaMethod::signature</h3>

<p>在某些严重依赖于QMetaObject内省系统的程序中，经常会使用QMetaMethod::signature API。在Qt 4，这个函数返回const char *。而在Qt 5，其返回值是动态构建的，所以需要进行一定的修改（因为不能返回局部变量的指针）。现在，等价的函数有一个不同的返回值（QByteArray），以及不同的名字（QMetaMethod::methodSignature）。仅仅改变函数名，会有运行时错误：</p>

<pre class="brush:cpp">
// 旧的Qt 4代码
// 返回的 const char * 赋值给本地变量，然后直接使用
const char *name = mm.signature();
otherApi(name);

// 新的Qt 5代码
const char *name = mm.methodSignature();
// name 会成为野指针！
// methodSignature() 返回的是 QByteArray，在函数返回时已经析构
otherApi(name); // 等着程序崩溃吧！
</pre>

<p>这个运行时bug可以通过在构建时添加<strong>QT&#95;NO&#95;CAST&#95;FROM&#95;BYTEARRAY</strong>来避免。这应该是在Qt 4就应该启用的。这个函数名的改变以及返回值的变化应该在迁移工作的一个独立步骤中修正。</p>

<h3>改变的virtual函数</h3>

<p>Qt 5中，少量virtual函数有了变化。这不会在迁移时构成编译错误（除非纯虚函数的改变），但是会在运行时引发异常（因为重写的函数不能被执行）。其中一个是，QAbstractItemView::dataChanged 信号有了一个参数。</p>

<p>我们有许多方法来解决这个问题。新的C++ 11标准有一个语法，能够指示一个类的特定函数是不是对父类同名函数的一个覆盖。使用这个语法，我们可以在迁移时使其成为编译错误。编译错误总是要比运行时错误好，因为它们更容易找到（事实上，它们是不能回避的）。</p>

<p>另外一种方法是，开启编译器警告。GCC可以对子类的函数隐藏了父类的虚函数提出警告（-Woverloaded-virtual）。我们可以在构建之前开启这个特性，这样就可以更加明显地找到问题。另外，始终采用最严格的编译器警告级别当然是值得推荐的做法，因此你应该将这个警告添加到你的构建系统的参数中。</p>

<h1>迁移之后</h1>

<p>所有的程序都是要维护的，而不仅仅是编写或者迁移完这么简单。当你把你的程序迁移到Qt 5之后，还有更多的步骤值得你去做。</p>

<p>我们不应该在同一个分支同时提供对Qt 4和Qt 5的支持。在结束了整个迁移之后，单元测试也能够全部通过，这就意味着，我们可以开始两个分支：基于Qt 4的和基于Qt 5的。原因之一就是能够使用那些在Qt 5废止了的Qt 4的API。</p>

<h3>移除对标记为废弃的函数的调用</h3>

<p>标记为deprecated的函数在Qt 5中还是存在的，但是可能会在未来消失。这种情况是Qt 5为了与Qt 4抱持兼容而保留的，就像Qt 4保留了Qt 3的支持一样。</p>

<p>我们应该尽快移除deprecated函数，因为它们会在编译时发出警告，这会与其它有用的警告混杂在一起，而新的API可能更快，可能用起来更方便。</p>

<h3>迁移到QML</h3>

<p>将已有的UI迁移到QML是可选的步骤，可以在迁移之前完成，也可以在迁移之后进行。</p>

<p>Qt 4提供的QML版本，在Qt 5中依然适用，名字为QtQuick1。不过，这仅供迁移用，以后也不会进行性能提升等。使用了这些的代码应该再迁移到QML2（以及Qt 5中的QtQuick API），以获得更好的性能。迁移到QML2更像是使用另外名字的 C++ API，同时要修改绘制自定义组件的方法。因为QML2使用的是scene-graph机制，而不是QPainter API（正是由于这个原因，才会导致性能的提升），自定义组件需要使用不同的 更新API进行绘制。</p>

<p><img src="http://www.kdab.com/wp-content/uploads/stories/kaddressbook-mobile-300x188.png" alt="使用了QML1的KDE PIM的Contacts Touch" /></p>

<h1>结论</h1>

<p>前面所说的从Qt 4迁移到Qt 5的步骤不是要求严格遵守的。在Qt 5正式发布之后，应该会有一个更加完整的列表。</p>

<p>另外需要注意的是，这篇文章关注的是（另人厌烦的）那些使用Qt 5构建应用程序所需要的步骤。然而关于升级时出现的运行时bug只字未提，而这才是迁移时真正花费时间的。目前一些KDE应用程序出现了一些微妙的bug急需处理：</p>

<p><img src="http://www.kdab.com/wp-content/uploads/stories/dolphin-300x209.png" alt="Dolphin About页面出现编码问题" /></p>

<p><img src="http://www.kdab.com/wp-content/uploads/stories/konqueror-300x197.png" alt="Konqueror菜单有小bug" /></p>

<p>在<a href="http://qt.gitorious.org/qt/qtbase/blobs/master/dist/changes-5.0.0">变更日志</a>中列出的边界条件的更改暗示了那些在Qt 5中有所不同的部分可能会在迁移代码中引发bug。</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qt.nokia.com.cn/2012/07/09/porting-from-qt-4-to-qt-5/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Qt 5的桌面组件</title>
		<link>http://labs.qt.nokia.com.cn/2012/06/27/desktop-components-for-qt-5/</link>
		<comments>http://labs.qt.nokia.com.cn/2012/06/27/desktop-components-for-qt-5/#comments</comments>
		<pubDate>Wed, 27 Jun 2012 07:20:16 +0000</pubDate>
		<dc:creator>齐亮</dc:creator>
				<category><![CDATA[qt-labs-chinese]]></category>
		<category><![CDATA[KDE]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://labs.qt.nokia.com.cn/?p=960</guid>
		<description><![CDATA[原文链接：Morten Johan Sørvig &#8211; Desktop Components for Qt 5 根据最新调查，桌面组件是大家最喜欢的Qt Quick 2组件。为了使它成为现实，我们已经把桌面组件项目迁移到了codereview.qt-project.org，并且现在就开始针对Qt Quick 1和2两个版本同时接受大家的贡献。目前已经有几个很好的贡献被接受了，与此同时Nokia的几个同事也已经加入这个项目。 目前，这些组件只是作为Qt Playground类型的项目托管，并且不会作为5.0的一部分而发布。它们将会单独发布，但是会和Qt 5的发布保持同步。在适当的时候，我们也许会把它变为Qt 5的一部分。 项目的细节都在wiki中。这里是一个快速开始的脚本： git clone https://git.gitorious.org/qtplayground/qtdesktopcomponents.git qtdesktopcomponents git checkout qt5 qmake make install cd qmldesktopviewer; qmake; make; cd.. qmldesktopviewer/qmldesktopviewer examples/TopLevel.qml 您想做一些贡献么？这里是一些需要完成的任务，其中包括： 添加一个菜单条组件 添加鼠标滚轮支持 为你最喜欢的平台提供风格美化 更新：树型视图！ 最后， 让我们看一些截屏图片（所有都基于Qt 5）： Windows Mac OS X KDE GNOME]]></description>
			<content:encoded><![CDATA[<p>原文链接：<a href="http://labs.qt.nokia.com/author/morten/">Morten Johan Sørvig</a> &#8211; <a href="http://labs.qt.nokia.com/2012/06/06/desktop-components-for-qt-5/">Desktop Components for Qt 5</a></p>

<p>根据最新<a href="http://qt-project.org/forums/viewthread/16693/">调查</a>，桌面组件是大家最喜欢的Qt Quick 2组件。为了使它成为现实，我们已经把桌面组件项目迁移到了<a href="https://codereview.qt-project.org/#q,project:playground/qtdesktopcomponents,n,z">codereview.qt-project.org</a>，并且现在就开始针对Qt Quick 1和2两个版本同时接受大家的贡献。目前已经有几个很好的贡献被接受了，与此同时Nokia的几个同事也已经加入这个项目。</p>

<p><span id="more-960"></span></p>

<p>目前，这些组件只是作为Qt Playground类型的项目托管，并且不会作为5.0的一部分而发布。它们将会单独发布，但是会和Qt 5的发布保持同步。在适当的时候，我们也许会把它变为Qt 5的一部分。</p>

<p>项目的细节都在<a href="http://qt-project.org/wiki/QtDesktopComponents">wiki</a>中。这里是一个快速开始的脚本：</p>

<pre class="code" brush="shell">
git clone https://git.gitorious.org/qtplayground/qtdesktopcomponents.git qtdesktopcomponents
git checkout qt5
qmake
make install
cd qmldesktopviewer; qmake; make; cd..
qmldesktopviewer/qmldesktopviewer examples/TopLevel.qml
</pre>

<p>您想做一些贡献么？这里是一些需要完成的任务，其中包括：</p>

<ul>
<li>添加一个菜单条组件</li>
<li>添加鼠标滚轮支持</li>
<li>为你最喜欢的平台提供风格美化</li>
<li>更新：树型视图！</li>
</ul>

<p>最后， 让我们看一些截屏图片（所有都基于Qt 5）：</p>

<ul>
<li><strong>Windows</strong></li>
</ul>

<p><img src="http://labs.qt.nokia.com/wp-content/uploads/2012/06/DesktopComponentsWin.png" alt="DesktopComponentsWin" title="DesktopComponentsWin" /></p>

<ul>
<li><strong>Mac OS X</strong></li>
</ul>

<p><img src="http://labs.qt.nokia.com/wp-content/uploads/2012/06/DesktopComponentsMac1.png" alt="DesktopComponentsMac" title="DesktopComponentsMac" /></p>

<ul>
<li><strong>KDE</strong></li>
</ul>

<p><img src="http://labs.qt.nokia.com/wp-content/uploads/2012/06/DesktopComponentsKDE.png" alt="DesktopComponentsKDE" title="DesktopComponentsKDE" /></p>

<ul>
<li><strong>GNOME</strong></li>
</ul>

<p><img src="http://labs.qt.nokia.com/wp-content/uploads/2012/06/DesktopComponentsGNOME.png" alt="DesktopComponentsGNOME" title="DesktopComponentsGNOME" /></p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qt.nokia.com.cn/2012/06/27/desktop-components-for-qt-5/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>源码必须是UTF-8，QString需要它</title>
		<link>http://labs.qt.nokia.com.cn/2012/05/16/source-code-must-be-utf-8-and-qstring-wants-it/</link>
		<comments>http://labs.qt.nokia.com.cn/2012/05/16/source-code-must-be-utf-8-and-qstring-wants-it/#comments</comments>
		<pubDate>Wed, 16 May 2012 08:31:16 +0000</pubDate>
		<dc:creator>Debao Zhang</dc:creator>
				<category><![CDATA[qtearth-blogs-chinese]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://labs.qt.nokia.com.cn/?p=942</guid>
		<description><![CDATA[原文链接：Thiago Macieira－ Source code must be UTF-8 and QString wants it 先前我讨论过源代码的编码问题，认为C++语言缺少一个必要的基本设置。尽管如此，从本周一开始，在某种程度上，Qt5现在已开始强制要求源代码必须是UTF-8。 将QString的8-bit成员函数所用的编码改为UTF-8的提交(commit)终于融入到qtbase代码仓库中。这正是我们为Qt5所规划的，从Robin Burchell移除QTextCodec::setCodecForCStrings开始的，一系列变更(changes)画上了完美的句号。但明确一点：QString内部仍采用UTF-16存储数据且不会改变。 为了理解这个变更是什么，我们需要回顾一点点历史。四年前，我写了一篇叫做“字符串理论(String Theory)”的博客来介绍QString的历史。我写到： 你的文件是何种编码？即便是UTF-8被广泛使用的今天，我们仍然不能依赖于这个事实(Windows下的文本编辑器是最糟糕的例子)。 在2008年，我们仍然与源代码中的UTF-8编码抗争，和我们在2003年所做的一样，当时QTextCodec::setCodecForCStrings被引入到Qt3。原因是，在当时，文本编辑器通常只使用操作系统的本地(locale)编码来保存代码，而且很少支持编写其它东西。由于Unicode尚未被广泛使用，从而导致人们使用各种不同的编码。考虑到数据交换只在使用相同编码的人(来自同一个国家，使用相同的操作系统)之间发生，这在当时也不是个问题。 时代已经改变了。源于90年代后期哪些不具备编码标示的协议很快就变得过时了或者增加这种标记(我记得当时Kopete的开发者正挣扎于如何恰当地解码ICQ消息，而且俄罗斯用户通常以乱码(mojibake)结束)。设计于21世纪的协议都有一个此类标示，而且很快基于某个Unicode transforms形成规范。 去年，当重新审视这个主题时，我写到： 都2011了，为什么我们仍将自己限制在ASCII？我是说，即使你只是用英文写不需要翻译的消息，有时你仍需要非ASCII码点(codepoint)，比如“微”符号(µ)，度符号(°)，版权符号(©)，甚至是欧元符号(€)。[...]。除此之外，现在是2011，文字交换的事实(de-facto)编码是UTF-8。 博客中下一行就是结论：在Qt5中，我们将把QString的8位(8-bit)成员函数的默认编码从Latin 1改为UTF-8(注意到，直到15天以后我们才开始思考Qt 5)。这就是我本周一的提交(commit)最终完成的事情。 这对你意味着什么呢？好吧，第一件事情是它依赖于你是否使用了这些成员方法。如果你编译源代码时使用了宏QT&#95;NO&#95;CAST&#95;FROM_ASCII和QT&#95;NO&#95;CAST&#95;TO&#95;ASCII，你将感受不到任何区别。我的意思真的是完完全全，彻彻底底：如果你使用了这些宏，你已经禁用了所有受我的变更所影响的函数。 如果你真的使用了被这些宏所禁用的函数，那么问题是这些字符串使用的何种编码。我在2008所做的假设现在仍然有效：源代码中的绝大多数字符串是7-bit，US-ASCII，英文文字。这些7-bit的文字完全不受影响：它将向往常一样被转换成QString的内部编码UTF-16。这可能会影响一点点性能，但就像我去年所说，我确实有优化UTF-8解码器的计划。尽管如此，如果你可以，我建议使用QLatin1String来封装这些字符串，尤其是你正将它们用于一个有QLain1String重载的QString的函数。 另一方面，如果你确实在QString的8-bit成员函数中使用了高位被设置的的文字，你可能需要修改你的代码。你要么用UTF-8重写你的代码，要么你需要用合适的QLatin1String或QTextCodec::toUnicode函数来封装这些字符串。我比较建议使用前一个选项：在你的源代码中使用UTF-8。你也将获得正确使用QStringLiteral的能力，无论如何，它需要源代码是UTF-8。 [作为历史的一个有趣的转折点，QStringLiteral的灵感源于我去年第二篇关于编码的博客——在本文前面所引用的要求改为UTF-8的第一部分之后，但它比本周一的变更更早地融入Qt 5之中。] 对于Qt自身的源码，我们已经决定应当只使用UTF-8，而且从几周前开始我一直在搜索并重写所有的非UTF-8的源码。 我将更进一步：如果你在自己的源码中不使用UTF-8，你需要自己负责。尽管使其工作是可能的，但不要向我们寻求帮助，也不要期待我们为其添加便利的函数。我也会忽略任何这种形式的争论“我的编辑器、IDE、OS、环境不支持UTF-8”。现在是2012而且我们生活在一个全球化的世界。任何此类的编辑器或环境应该留在属于它的地方：一个致力于上世纪80年代和90年代的博物馆。 Unicode万岁！]]></description>
			<content:encoded><![CDATA[<p>原文链接：<a href="http://www.macieira.org/blog/">Thiago Macieira</a>－ <a href="http://www.macieira.org/blog/2012/05/source-code-must-be-utf-8-and-qstring-wants-it/">Source code must be UTF-8 and QString wants it </a></p>

<p><a href="http://labs.qt.nokia.com/2011/03/26/on-utf-8-latin-1-and-charsets/">先前</a>我讨论过源代码的编码问题，认为C++语言缺少一个必要的基本设置。尽管如此，从本周一开始，在某种程度上，Qt5现在已开始强制要求源代码必须是UTF-8。</p>

<p>将QString的8-bit成员函数所用的编码改为UTF-8的提交(commit)终于融入到<a href="http://qt.gitorious.org/qt/qtbase">qtbase代码仓库</a>中。这正是我们为Qt5所规划的，从Robin Burchell移除<a href="http://qt-project.org/doc/qt-4.8/qtextcodec.html#setCodecForCStrings">QTextCodec::setCodecForCStrings</a>开始的，一系列变更(changes)画上了完美的句号。但明确一点：QString内部仍采用UTF-16存储数据且不会改变。</p>

<p><span id="more-942"></span></p>

<p>为了理解这个变更是什么，我们需要回顾一点点历史。四年前，<a href="http://labs.qt.nokia.com/2008/04/28/string-theory/">我写了一篇叫做“字符串理论(String Theory)”的博客</a>来介绍QString的历史。我写到：</p>

<blockquote>你的文件是何种编码？即便是UTF-8被广泛使用的今天，我们仍然不能依赖于这个事实(Windows下的文本编辑器是最糟糕的例子)。</blockquote>

<p>在2008年，我们仍然与源代码中的UTF-8编码抗争，和我们在2003年所做的一样，当时<a href="http://doc.trolltech.com/3.3/qtextcodec.html#setCodecForCStrings">QTextCodec::setCodecForCStrings</a>被引入到Qt3。原因是，在当时，文本编辑器通常只使用操作系统的本地(locale)编码来保存代码，而且很少支持编写其它东西。由于Unicode尚未被广泛使用，从而导致人们使用各种不同的编码。考虑到数据交换只在使用相同编码的人(来自同一个国家，使用相同的操作系统)之间发生，这在当时也不是个问题。</p>

<p>时代已经改变了。源于90年代后期哪些不具备编码标示的协议很快就变得过时了或者增加这种标记(我记得当时Kopete的开发者正挣扎于如何恰当地解码ICQ消息，而且俄罗斯用户通常以<a href="http://en.wikipedia.org/wiki/Mojibake">乱码(mojibake)</a>结束)。设计于21世纪的协议都有一个此类标示，而且很快基于某个Unicode transforms形成规范。</p>

<p>去年，当<a href="http://labs.qt.nokia.com/2011/03/25/qstrings-and-unicode-optimising-qstringfromutf8/">重新审视这个主题</a>时，我写到：</p>

<blockquote>都2011了，为什么我们仍将自己限制在ASCII？我是说，即使你只是用英文写不需要翻译的消息，有时你仍需要非ASCII码点(codepoint)，比如“微”符号(µ)，度符号(°)，版权符号(©)，甚至是欧元符号(€)。[...]。除此之外，现在是2011，文字交换的事实(de-facto)编码是UTF-8。</blockquote>

<p>博客中下一行就是结论：在Qt5中，我们将把QString的8位(8-bit)成员函数的默认编码从Latin 1改为UTF-8(注意到，直到15天以后我们才开始思考Qt 5)。这就是我本周一的提交(commit)最终完成的事情。</p>

<p>这对你意味着什么呢？好吧，第一件事情是它依赖于你是否使用了这些成员方法。如果你编译源代码时使用了宏<a href="http://qt-project.org/doc/qt-4.8/qstring.html#QT_NO_CAST_FROM_ASCII">QT&#95;NO&#95;CAST&#95;FROM_ASCII</a>和<a href="http://qt-project.org/doc/qt-4.8/qstring.html#QT_NO_CAST_TO_ASCII">QT&#95;NO&#95;CAST&#95;TO&#95;ASCII</a>，你将感受不到任何区别。我的意思真的是完完全全，彻彻底底：如果你使用了这些宏，你已经禁用了所有受我的变更所影响的函数。</p>

<p>如果你真的使用了被这些宏所禁用的函数，那么问题是这些字符串使用的何种编码。我在2008所做的假设现在仍然有效：源代码中的绝大多数字符串是7-bit，US-ASCII，英文文字。这些7-bit的文字完全不受影响：它将向往常一样被转换成QString的内部编码UTF-16。这可能会影响一点点性能，但就像我<a href="http://labs.qt.nokia.com/2011/03/25/qstrings-and-unicode-optimising-qstringfromutf8/">去年所说</a>，我确实有优化UTF-8解码器的计划。尽管如此，如果你可以，我建议使用<a href="http://qt-project.org/doc/qt-4.8/qlatin1string.html">QLatin1String</a>来封装这些字符串，尤其是你正将它们用于一个有QLain1String重载的QString的函数。</p>

<p>另一方面，如果你确实在QString的8-bit成员函数中使用了高位被设置的的文字，你可能需要修改你的代码。你要么用UTF-8重写你的代码，要么你需要用合适的<a href="http://qt-project.org/doc/qt-4.8/qlatin1string.html">QLatin1String</a>或<a href="http://qt-project.org/doc/qt-4.8/qtextcodec.html#toUnicode-4">QTextCodec::toUnicode</a>函数来封装这些字符串。我比较建议使用前一个选项：在你的源代码中使用UTF-8。你也将获得正确使用QStringLiteral的能力，无论如何，它需要源代码是UTF-8。</p>

<p>[作为历史的一个有趣的转折点，QStringLiteral的灵感源于我去年<a href="http://labs.qt.nokia.com/2011/03/26/on-utf-8-latin-1-and-charsets/">第二篇</a>关于编码的博客——在本文前面所引用的要求改为UTF-8的第一部分之后，但它比本周一的变更更早地融入Qt 5之中。]</p>

<p>对于Qt自身的源码，我们已经决定应当只使用UTF-8，而且从几周前开始我一直在搜索并重写所有的非UTF-8的源码。
我将更进一步：如果你在自己的源码中不使用UTF-8，你需要自己负责。尽管使其工作是可能的，但不要向我们寻求帮助，也不要期待我们为其添加便利的函数。我也会忽略任何这种形式的争论“我的编辑器、IDE、OS、环境不支持UTF-8”。现在是2012而且我们生活在一个全球化的世界。任何此类的编辑器或环境应该留在属于它的地方：一个致力于上世纪80年代和90年代的博物馆。</p>

<p>Unicode万岁！</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qt.nokia.com.cn/2012/05/16/source-code-must-be-utf-8-and-qstring-wants-it/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>QLALR探险——使用QLALR生成一个文字探险游戏的解析器</title>
		<link>http://labs.qt.nokia.com.cn/2012/04/25/qlalr-adventures/</link>
		<comments>http://labs.qt.nokia.com.cn/2012/04/25/qlalr-adventures/#comments</comments>
		<pubDate>Wed, 25 Apr 2012 08:26:51 +0000</pubDate>
		<dc:creator>齐亮</dc:creator>
				<category><![CDATA[qt-quarterly-chinese]]></category>
		<category><![CDATA[QLALR]]></category>

		<guid isPermaLink="false">http://labs.qt.nokia.com.cn/?p=924</guid>
		<description><![CDATA[原文链接 Geir Vattekar &#8211; QLALR Adventures &#8211; Using QLALR to generate a parser for a text adventure QLALR是Qt所提供的应用程序之一，它是Qt解析程序生成器。过去它已经被用于Qt Script中，现在它还对QML的JavaScript和Qt中的XML流读取负责。很遗憾地是，因为它缺少文档，大多数Qt用户都不知道它。这篇文章就试图对这一问题进行补救。 QLALR可以根据一个按特有语法写成的文件生成与之匹配的C++代码。这个被接受的语法就是LALR，例如，一个前置口令。和yacc这样的解析程序生成器一样，QLALR对于处理联系和区别都很有帮助（例如变换/减少冲突）。在这里，我们不会讨论太深入的问题，只是来看看如何简单的使用QLALR来实现一个小型语言的解析器。 Plover（珩科鸟） 为了找到一个合适的示例语言，让我们回到上个世纪八十年代，那个时候文字探险（译者注：就是MUD了）还闪耀着光芒。文字探险就是一种玩家们通过输入命令进行交互的游戏。这些命令通常是比真实的人类语言简单得多的一种语言，通常情况下使用的是一种简化的伪英语。这种语法是典型的简单精确。因此我们发现它作为一个QLALR的实例非常合适。 我们将把我们的这种语言称作Plover（在那个用文字探险的时代，玩过的朋友都会眼前一亮的一个名字）。让我们来看几个Plover句子。 north go north eat the tasty apple put orange peel in the trash bin 这里是BNF（巴科斯范式）格式的一个完整Plover语法： Input ::= Sentence Sentence ::= SingleVerbSentence &#124; OneNounSentence &#124; TwoNounSentence SingleVerbSentence ::= 'go' SingleVerb &#124; SingleVerb SingleVerb [...]]]></description>
			<content:encoded><![CDATA[<p>原文链接 Geir Vattekar &#8211; <a href="http://qt.nokia.com/include/archive/qtquarterly/qlalr-adventures">QLALR Adventures &#8211; Using QLALR to generate a parser for a text adventure</a></p>

<p>QLALR是Qt所提供的应用程序之一，它是Qt解析程序生成器。过去它已经被用于Qt Script中，现在它还对QML的JavaScript和Qt中的XML流读取负责。很遗憾地是，因为它缺少文档，大多数Qt用户都不知道它。这篇文章就试图对这一问题进行补救。</p>

<p>QLALR可以根据一个按特有语法写成的文件生成与之匹配的C++代码。这个被接受的语法就是<a href="http://en.wikipedia.org/wiki/LALR" title="LALR解析器">LALR</a>，例如，一个前置口令。和yacc这样的解析程序生成器一样，QLALR对于处理联系和区别都很有帮助（例如变换/减少冲突）。在这里，我们不会讨论太深入的问题，只是来看看如何简单的使用QLALR来实现一个小型语言的解析器。</p>

<p><span id="more-924"></span></p>

<h2>Plover（珩科鸟）</h2>

<p>为了找到一个合适的示例语言，让我们回到上个世纪八十年代，那个时候文字探险（译者注：就是MUD了）还闪耀着光芒。文字探险就是一种玩家们通过输入命令进行交互的游戏。这些命令通常是比真实的人类语言简单得多的一种语言，通常情况下使用的是一种简化的伪英语。这种语法是典型的简单精确。因此我们发现它作为一个QLALR的实例非常合适。</p>

<p>我们将把我们的这种语言称作Plover（在那个用文字探险的时代，玩过的朋友都会眼前一亮的一个名字）。让我们来看几个Plover句子。</p>

<pre class="code">
north
go north
eat the tasty apple
put orange peel in the trash bin
</pre>

<p>这里是BNF（巴科斯范式）格式的一个完整Plover语法：</p>

<pre class="code">
Input ::= Sentence

Sentence ::= SingleVerbSentence
          |  OneNounSentence
          |  TwoNounSentence

SingleVerbSentence  ::= 'go' SingleVerb
                     |  SingleVerb

SingleVerb ::= 'north' | 'south' | 'west' | 'east'

OneNounSentence ::= OneNounVerb Noun

OneNounVerb ::= 'eat'

Noun ::= 'the' ObjectNameList
      | ObjectNameList

ObjectNameList ::= OBJECTNAME
                |  ObjectNameList OBJECTNAME

TwoNounSentence ::= TwoNounVerb Noun Preposition Noun

TwoNounVerb ::= 'put'

Preposition ::= 'in'
</pre>

<p><code>OBJECTNAME</code>是一个可以为任意单词的口令，就像编程语言中的变量名一样。其它的口令大家通过拼写就知道意思了。</p>

<h2>QLALR规范</h2>

<p>QLALR的输入是一个包含语法、口令定义和产品完成时所执行的C++代码的文件（后缀为.g），可以用于构建一个符号栈并且保持对解析状态跟踪。另外，口令管理器必须单独实现，要么在这个.g文件中，要么在一个单独的C++源文件中。</p>

<p>让我们先来看看这么实现解析的类的定义。</p>

<pre class="code">
class CommandInterpreter : public $table
{

public:
    CommandInterpreter();
    ~CommandInterpreter();

    Command parse();

    int nextToken();

    void setInput(const QString &#038;input);

    inline void reallocateStack();

    inline QString &#038;sym(int index)
    { return sym_stack [tos + index - 1]; }

private:
    int tos;
    QStringList tokens;
    QVector<QString> sym_stack;
    QVector<int> state_stack;
    QString yylval;
};
</pre>

<p>这个类并不是生成的。我们用它来为Plover创建一个方便的前端。<code>$table</code>将会被QLALR所生成的类替代，其中包含了我们在<code>parse()</code>函数中所需要的常量、表和函数。</p>

<p>QLALR使用一个状态栈这样的有限的状态机实现了它的解析。我们自己保存这个栈，当然QLALR会告诉我们哪些状态需要推送到这个栈中和什么时候再次弹出这些状态。<code>tos</code>是用来指向这个状态栈的顶端。稍后会就这一点进一步解释。</p>

<p><code>sym_stack</code>是一个符号栈，我们在这里保存了一些QString。<code>sym()</code>用来获取和当前产品相关的值。当遇到一个<code>OBJECTNAME</code>时，口令管理器就会设置<code>yylval</code>。我们用它来更新符号栈。</p>

<p>要开始一个命令（<code>Command</code>）的解析，我们需要设置输入（<code>setInput()</code>）并且调用<code>parse()</code>，它会在解析的时候为我们构建<code>Command</code>。为了完整起见，我们先展示一下<code>Command</code>的类定义（这一部分没有在.g文件中声明）。</p>

<pre class="code">
class Command
{

public:
    enum Verb { Eat, Go, Put, North, East, West, South };
    enum Preposition { In };
    enum State { Valid, Invalid };

    State state;
    QString errorMessage;

    Verb verb;
    QList<QString> nounNames; // First noun
    Preposition preposition;
    QList<QString> secondNames; // Second noun
};
</pre>

<p>让我们来继续看QLALR的输入文件：</p>

<pre class="code">
%parser CommandParser
%merged_output commandparser.cpp
%start Input
</pre>

<p><code>%parser</code>给出了由QLALR生成的类的名称。<code>%merged_output</code>规定了我们只想输出一个文件，它会同时包含.g文件中的C++的定义和实现代码。如果您想生成单独的头文件和实现文件，也可以使用<code>%decl</code>和<code>%impl</code>。<code>%start</code>规定了产品解析的开始位置。输出到声明部分的代码由<code>/:</code>和<code>:/</code>包含，实现部分由<code>/.</code>和<code>./</code>包含。</p>

<p>然后我们定义了这些口令：</p>

<pre class="code">
-- The verbs

%token EAT "eat"
%token GO "go"
%token NORTH "north"
%token EAST "east"
%token SOUTH "south"
%token WEST "west"
%token PUT "put"

-- The preposition

%token IN "in"

-- Object names

%token THE "the"

%token OBJECTNAME "object"
</pre>

<p>口令由<code>%token</code>设定。它们将会变为生成的解析器的常量，并且会由口令管理器返回。注意这里给定的字符串只是用于错误处理，例如在解析自身的时候它们并不会被用到。</p>

<p>对于我们这个小语言，我们通过<code>nextToken()</code>函数实现了我们自己的口令管理器。因为我们是在解析期间自己调用的这个函数，如果需要的话，也可以使用任意的语法分析程序生成器，例如lex。</p>

<pre class="code">
int CommandInterpreter::nextToken()
{
    if (tokens.isEmpty()) {
        return EOF_SYMBOL;
    }

    QString nextToken = tokens.takeFirst();

    nextToken = nextToken.toLower();

    if (nextToken == "eat") {
        return CommandParser::EAT;
    }

    ...

    if (nextToken == "the") {
        return CommandParser::THE;
    }

    yylval = nextToken;
    return CommandParser::OBJECTNAME;
}
</pre>

<p><code>tokens</code>是一个QVector<QString>，包含了Plover语句的单词（例如[ 'put' 'gold' 'in' 'chest' ]）。正如您所见到的，当识别出认识的口令，就简单地返回口令常量。注意当遇到一个对象名称的时候，就保存这个口令的值。后面会用到它。</p>

<h2>语法</h2>

<p>在这一部分中，我们将会看看Plover语法的实现。也就是在这里，QLALR（或者其它做同样事情的解析程序生成器）的使用真正帮到我们了。</p>

<pre class="code">
Input: Sentence ;

Sentence: GO SingleVerbSentence ;
Sentence: SingleVerbSentence ;
Sentence: OneNounSentence ;
Sentence: TwoNounSentence ;
</pre>

<p>产品的每一部分（或者是一个口令或者是另外一个产品）是由空格（whitespace）分隔的。如果这个产品有其它选择，它们会按照上面所显示的<code>Sentence</code>产品那样给出。</p>

<p>当一个产品完成时，我们可以插入代码：</p>

<pre class="code">
ObjectName: OBJECTNAME ;
/.
    case $rule_number: {
        sym(1) = yylval;
    } break;
./
</pre>

<p><code>/.</code>和<code>./</code>中间的代码会被插入到生成的解析器中，并且当解析器匹配到之前的产品时执行这一代码。<code>$rule_number</code>将会被这个语法中代表这个产品的数字所替代。</p>

<p><code>sym()</code>函数会访问符号栈。它会获取和当前产品相关的值，例如<code>sym(1)</code>总是代表当前产品的第一个元素。我们的符号栈是由一组QString组成的。我们只保存<code>OBJECTNAME</code>的值，所以对于语法中的其它部分这个栈总是包含空字符串。</p>

<p>我们将不会查看所有的产品，因为我们已经用BNF格式展示了Plover语法。但在我们离开产品之前，让我们看看对象和句子是如何被解析的吧。</p>

<pre class="code">
ObjectList: ObjectList ObjectName ;

Noun: THE ObjectList ;
Noun: ObjectList ;

ObjectList: ObjectName ;
/.
    case $rule_number: {
        command.nounNames.append(sym(1));
    } break;
./

...

TwoNounSentence: PUT Noun IN Second ;
/.
    case $rule_number: {
        command.verb = Command::Put;
        command.preposition = Command::In;
    } break;
./
</pre>

<p>注意产品的每一个部分都将会在符号栈中拥有一个单独的值。</p>

<h2>parse()函数</h2>

<p>在这个<code>parse()</code>函数中，我们使用了由QLALR所生成的表来进行真正的解析。QLALR还生成了一些帮助函数。</p>

<p>这个解析函数有三个部分：</p>

<ul>
<li>找到一个产品</li>
<li>执行找到这个产品的代码（正如我们之前所看到的）</li>
<li>处理解析错误</li>
</ul>

<pre class="code">
Command CommandInterpreter::parse()
{
    Command command;

    const int INITIAL_STATE = 0;
    int yytoken = -1;

    tos = 0;
    state_stack[++tos] = INITIAL_STATE;

    while (true) {
        const int state = state_stack.at(tos);
        if (yytoken == -1 &#038;&#038; - TERMINAL_COUNT != action_index [state] ) {
            yytoken = nextToken();
        }

        int act = t_action (state, yytoken);
        if (act == ACCEPT_STATE) {
            command.state = Command::Valid;
            return command;

        } else if (act > 0) {
            if (++tos == state_stack.size())
                reallocateStack();
            state_stack[tos] = act;
            yytoken = -1;
        } else if (act < 0) {
</pre>

<p>这部分看起来也许有一点可怕并且难以理解，但是不要怕，这部分代码通常对于解析器来说都是一样的。所以就把它们复制粘贴一下，然后就过去了。这里的要点是<code>t_action()</code>会从当前状态找到下一个状态。当它需要一个新的口令时，它会返回正值；当一个产品完成时，它会返回负值。零值意味着在语法中当前口令失败（也就是一个错误）。</p>

<p>这个while循环会一直运行，知道发生错误或者到达<code>ACCEPT_STATE</code>（例如，输入和语法匹配，并且我们找到了一个有效的命令）。</p>

<pre class="code">
        } else if (act < 0) {
            int r = -act - 1;
            tos -= rhs[r];
            act = state_stack.at(tos++);

            switch(r) {
./

Input: Sentence ;

...

/.
            } // of the switch

            state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT);
        } else {
</pre>

<p>在一个产品被找到并且相应的代码（如果有的话）执行之后，我们删除这个已经完成的产品所使用的状态，并且继续处理接下的产品。这是通过更新<code>tos</code>和调用<code>nt_action()</code>完成的，<code>nt_action()</code>会获取在新的<code>tos</code>位置的动作。再一次，简单地复制和粘贴这部分代码到您的解析器就可以了。</p>

<p>最后，我们来看看错误处理：
<pre class="code">
      } else {
         QString m<em>errorMessage;
          int ers = state;
          int shifts = 0;
          int reduces = 0;
          int expected</em>tokens[3];
          for (int tk = 0; tk &lt; TERMINAL<em>COUNT; ++tk) {
              int k = t</em>action(ers, tk);</p>

<pre><code>          if (! k)
            continue;
          else if (k &lt; 0)
            ++reduces;
          else if (spell[tk]) {
              if (shifts &lt; 3)
                expected_tokens[shifts] = tk;
              ++shifts;
          }
      }
</code></pre>

<p>...
</pre></p>

<p>为了在特定状态的语法中检查哪些口令被确认了，我们对所拥有的全部口令调用<code>t_action()</code>，并且之后把接受的口令添加到一个数组中，使其可以用于错误信息。在这里我们不用再显示错误信息代码的部分。Plover的错误信息对于其它语言没有什么用处。例如“我不理解这句话”这样的消息对于C编译器输出来说时非常恼人的。我们为口令所指定的字符串已经被添加到一个数组<code>spell</code>中，数组的索引值和口令值一致。因此如果要获取一个口令的文本名称，可以写<code>spell[PloverParser::TO]</code>。</p>

<h2>更进一步</h2>

<p>如果想要一个更为复杂的实例，您可以看看Qt Script（通常发布在Qt 4的src/script/parser目录下）中的.g文件。您还可以在util/qlalr/examples目录下找到4个实例。如果您的目标是成为QLALR的专家，可以研究一下src/corelib/xml/qxmlstream.g。</p>

<h2>源代码</h2>

<p>本文中提到的实例的源代码可以在Qt Quarterly的网站下载：<a href="http://qt.nokia.com/doc/qq/qq33-qlalr.zip">qq33-qlalr.zip</a>。</p>

<h2>关于作者</h2>

<p>Geir Vattekar是Nokia, Qt的一名科技作者。在写作之余，他很喜欢交互科幻（文字探险）和函数编程。</p>

<p>译者注：大家还可以参考一下这篇文章 <a href="http://labs.qt.nokia.com/author/kent/">Kent Hansen</a> - <a href="http://labs.qt.nokia.com/2007/10/08/developer-dazetm-presents-a-closer-look-at-qlalr/">Developer Daze(tm) presents: A Closer Look at QLALR</a></p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qt.nokia.com.cn/2012/04/25/qlalr-adventures/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Qt 5, C++和Qt Widget</title>
		<link>http://labs.qt.nokia.com.cn/2012/04/23/qt-5-c-and-qt-widgets/</link>
		<comments>http://labs.qt.nokia.com.cn/2012/04/23/qt-5-c-and-qt-widgets/#comments</comments>
		<pubDate>Mon, 23 Apr 2012 07:15:45 +0000</pubDate>
		<dc:creator>Zhen Zeng</dc:creator>
				<category><![CDATA[qt-labs-chinese]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Contributors]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://labs.qt.nokia.com.cn/?p=910</guid>
		<description><![CDATA[原文链接 Lars Knoll &#8211; Qt 5, C++ and Qt Widgets 我们发现大家非常关注我们在Qt5中对C++及QWidget所作出的承诺并且有很多疑问。我想现在正好可以在这里就就大家所关注的热点问题进行一下解答。 Qt 5 alpha文章重点讲了我们在Qt 5加入并启用的东西。 让我在这里明确的说明一下： QWidget及其全部派生类是桌面Qt 5的核心部分 您仍然完全可以像在Qt 4.x时那样编写您的程序。 我们承诺我们会尽最大努力的保证与Qt 4.x的源码兼容性。这当然包括了QWidget和您用C++写的程序。这些东西都没消失。是的，我们的Qt 5中的Qt Widgets模块现在已经被标记为“完成”，这意味着此时此刻我们没有人在为这个模块的新特性工作了。但是如果有一天这领域有人感兴趣了或者需要进行更多开发了的时候，上述的情况就会发生改变。 Qt 5中我们增加了QML这种应用程序开发方式。我个人坚信，假以时日，越来越多的程序会是用这种新方式写成的，就像我相信对长远来说，QML是一个更好的方法。 像Windows 8 Metro UI这样的新用户界面并不能简单的加入到我们现有的QWidget基础架构中。使用QWidget在这些用户界面上添加各种动画的支持真的极其困难，这是由于QWidget是在好多年前为了大量的以静态为主要单元的用户界面而设计的。 流畅的动画用户界面现在已经存在于那些智能电话和平板设备上了，也开始渐渐出现在桌面环境了。而这些用QWidget基础架构也很难简单实现。 这意味着我们需要点新东西。QML/Qt Quick就是我们想到的解决问题的方法。这也是我们对这方面感兴趣的原因。 过去几年我们使用QML的经验告诉我们QML是创建UI的长期优秀技术。如果您想，您可以简单的把它用作.ui文件的强力替代。同时您仍然可以在需要时用JacaScript写一些程序逻辑。 这确实是由每个人对Qt 5所给出的选项做出选择，并以自己最喜欢的方式去使用它。 C++是且会一直是我们的主要编程语言 我们做了显著的工作，添加了很多新的C++ API。我们在许多地方添加了C++11的支持。而且我们还会持续的做这些事情，因为很长一段时间以来Qt写的大型程序大多数都是C++写成的。这没什么不好的。 我们对Qt 5所做的是混入了另外一种选择。我们想让JavaScript的使用得到像C++一样的支持。我们并不是让它变成更优越的或者唯一的支持方式。这是件好事，它为您编写应用程序提供了新的选择。 只要你想，就可以在QML内加入小段的程序逻辑。这种方式可以快速的做出原型，之后也可以在最终实现上替换为C++实现。在QML中插入小段程序逻辑赋予了程序脚本运行的能力。而且对于很多程序而言，它同样给出了用QML与JavaScript写出程序绝大部分的可能。 总结 使用Qt 5，如果您希望像以往那样使用Qt，请继续。这是一个得到完整支持的编程方式。 但是我相信我们在更长远的未来会需要更多的东西。对应用程序UI的想法会大幅改变，尤其是创建面向消费者的程序的时候。 我们希望Qt能保持稳定，那必须得有解决方法。而这就是Qt 5所全部考虑的。 Cheers， Lars]]></description>
			<content:encoded><![CDATA[<p>原文链接 <a href="http://labs.qt.nokia.com/author/lars/">Lars Knoll</a> &#8211; <a href="http://labs.qt.nokia.com/2012/04/18/qt-5-c-and-qt-widgets/">Qt 5, C++ and Qt Widgets</a></p>

<p>我们发现大家非常关注我们在Qt5中对C++及QWidget所作出的承诺并且有很多疑问。我想现在正好可以在这里就就大家所关注的热点问题进行一下解答。</p>

<p><a href="http://labs.qt.nokia.com.cn/2012/04/16/qt-5-alpha/">Qt 5 alpha</a>文章重点讲了我们在Qt 5加入并启用的东西。</p>

<p><span id="more-910"></span></p>

<p>让我在这里明确的说明一下：</p>

<h2>QWidget及其全部派生类是桌面Qt 5的核心部分</h2>

<p>您仍然完全可以像在Qt 4.x时那样编写您的程序。</p>

<p>我们承诺我们会尽最大努力的保证与Qt 4.x的源码兼容性。这当然包括了QWidget和您用C++写的程序。这些东西都没消失。是的，我们的Qt 5中的Qt Widgets模块现在已经被标记为“完成”，这意味着此时此刻我们没有人在为这个模块的新特性工作了。但是如果有一天这领域有人感兴趣了或者需要进行更多开发了的时候，上述的情况就会发生改变。</p>

<p>Qt 5中我们增加了QML这种应用程序开发方式。我个人坚信，假以时日，越来越多的程序会是用这种新方式写成的，就像我相信对长远来说，QML是一个更好的方法。</p>

<p>像Windows 8 Metro UI这样的新用户界面并不能简单的加入到我们现有的QWidget基础架构中。使用QWidget在这些用户界面上添加各种动画的支持真的极其困难，这是由于QWidget是在好多年前为了大量的以静态为主要单元的用户界面而设计的。</p>

<p>流畅的动画用户界面现在已经存在于那些智能电话和平板设备上了，也开始渐渐出现在桌面环境了。而这些用QWidget基础架构也很难简单实现。</p>

<p>这意味着我们需要点新东西。QML/Qt Quick就是我们想到的解决问题的方法。这也是我们对这方面感兴趣的原因。</p>

<p>过去几年我们使用QML的经验告诉我们QML是创建UI的长期优秀技术。如果您想，您可以简单的把它用作.ui文件的强力替代。同时您仍然可以在需要时用JacaScript写一些程序逻辑。</p>

<p>这确实是由每个人对Qt 5所给出的选项做出选择，并以自己最喜欢的方式去使用它。</p>

<h2>C++是且会一直是我们的主要编程语言</h2>

<p>我们做了显著的工作，添加了很多新的C++ API。我们在许多地方添加了C++11的支持。而且我们还会持续的做这些事情，因为很长一段时间以来Qt写的大型程序大多数都是C++写成的。这没什么不好的。</p>

<p>我们对Qt 5所做的是混入了另外一种选择。我们想让JavaScript的使用得到像C++一样的支持。我们并不是让它变成更优越的或者唯一的支持方式。这是件好事，它为您编写应用程序提供了新的选择。</p>

<p>只要你想，就可以在QML内加入小段的程序逻辑。这种方式可以快速的做出原型，之后也可以在最终实现上替换为C++实现。在QML中插入小段程序逻辑赋予了程序脚本运行的能力。而且对于很多程序而言，它同样给出了用QML与JavaScript写出程序绝大部分的可能。</p>

<h2>总结</h2>

<p>使用Qt 5，如果您希望像以往那样使用Qt，请继续。这是一个得到完整支持的编程方式。</p>

<p>但是我相信我们在更长远的未来会需要更多的东西。对应用程序UI的想法会大幅改变，尤其是创建面向消费者的程序的时候。</p>

<p>我们希望Qt能保持稳定，那必须得有解决方法。而这就是Qt 5所全部考虑的。</p>

<p>Cheers，<br />
Lars</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qt.nokia.com.cn/2012/04/23/qt-5-c-and-qt-widgets/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Qt 5 Alpha</title>
		<link>http://labs.qt.nokia.com.cn/2012/04/16/qt-5-alpha/</link>
		<comments>http://labs.qt.nokia.com.cn/2012/04/16/qt-5-alpha/#comments</comments>
		<pubDate>Mon, 16 Apr 2012 13:15:12 +0000</pubDate>
		<dc:creator>Zhen Zeng</dc:creator>
				<category><![CDATA[qt-labs-chinese]]></category>
		<category><![CDATA[Qt5]]></category>

		<guid isPermaLink="false">http://labs.qt.nokia.com.cn/?p=896</guid>
		<description><![CDATA[原文链接 Lars Knoll &#8211; Qt 5 Alpha 今天我们发布了Qt 5的Alpha版本，这是自进驻Qt Project以来推出的第一个主要版本。大家的努力工作使得这个发布成为可能。这个alpha版本大量的工作与引入的特性是由那些非Nokia员工所贡献的。很高兴的看到这个项目已经成为一个交流的平台，能让人们共同推进Qt。 此次Qt 5 Alpha发布的主要目的是获取反馈以帮助我们改进以后的发布。对于Alpha版，我们着重于Qt Essential模块，这些模块构成了Qt5提供的功能的基础。。 Alpha版本可以在http://qt-project.org/wiki/Qt-5-Alpha下载。请注意此alpha版只以源码形式的发布，没有可供下载的二进制版本，所以您得自己编译二进制文件。编译介绍参见http://qt-project.org/wiki/Qt-5-Alpha-building-instructions 自从去年5月我在一篇博客中概述了这个想法以来，我们已经在Qt 5上工作了差不多9个月了。那篇博客讲了我们在Qt 5中的几个目标，现在我想稍微反映些我们已经实现的部分。 理念 有一个基础的理念引领了大部分的Qt 5开发工作： ”Qt 5应当成为全新应用开发方式的基础。 一方面使用C++提供本地化Qt的全部能力，同时重点应当转移到一个模型上，这个模型使C++主要被用来实现Qt Quick模块化的后台功能。“ 我要说的是我们在Qt 5上有一个好方法向着这个理念靠近。这个模型在那些UI是全屏的嵌入式Qt上工作良好。对于桌面环境，我们已经针对所需的这个模型打下了许多基础，但是我们在5.1或者5.2发布的时候才能确切地让这个模型可用。 开放的开发 我们希望在开放中开发Qt 5，围绕着一个强健的社区。自推出qt-project.org以来，我们看见了一个充满活力的社区，并且我们在Qt 5中的许多补丁与新特性都是由社区提供的。 架构的四大变化 我们已经着手对四个主要的Qt内部架构进行修改： 把全部的Qt接口迁移到Qt Platform Abstraction(QPA)层之上 —— 使得Qt能更容易移植到另外的视窗系统和设备上 使用QPA，我们从根本上改变了Qt如何集成相关操作系统的视窗环境。QPA在Qt 4.8中作为QWS/Qt嵌入式的一种替代引入，但是现在完全使用在所有平台上。这个迁移带来了大量的工作并且迫使我们重写了很大一部分的纯平台相关的代码。但是它也帮助我们创造了一个更干净的架构，使得平台依赖代码能够得到很好的抽象。可以看到，新的抽象化能显著地简化对于新视窗系统的集成工作，并且为QNX，Android和IOS编写的后台证明了这点。 重新设计了图形堆栈 &#8211; 与Qt 4相比提高了性能，使用Qt Quick和OpenGL (ES) 2.0 Qt 5为Qt Quick引入了全新的图形架构，使用了基于OpenGL的场景图（Scenegraph）。最低需求：OpenGL (ES) 2.0。QtGui现在包含了一组QOpenGL&#42;类，用以替代老的QGL&#42;类（为了兼容性这些类仍然可以使用）。我们还引入了一个比QApplication更轻量级的新类QGuiApplication和一个处理屏幕上顶层窗口的类QWindow。以QWidget为基础的那些类仍然像Qt 4.x一样工作，基于QPainter。然后QPainter比起以前支持更少的后端。它现在限制了于使用软件光栅（Raster bankend）来绘制屏幕、像素与图像，一个OpenGL后端提供GL接口以及一个提供PDF生成与打印的后端。平台依赖的后端比如X11或者CoreGraphics已经去掉了。这使得我们可以引入新的长期支持的图形架构的同时保证Qt 4.x的QWidget部分的完整兼容性。 [...]]]></description>
			<content:encoded><![CDATA[<p>原文链接 <a href="http://labs.qt.nokia.com/author/lars/">Lars Knoll</a> &#8211; <a href="http://labs.qt.nokia.com/2012/04/03/qt-5-alpha/">Qt 5 Alpha</a></p>

<p>今天我们发布了Qt 5的Alpha版本，这是自进驻Qt Project以来推出的第一个主要版本。大家的努力工作使得这个发布成为可能。这个alpha版本大量的工作与引入的特性是由那些非Nokia员工所贡献的。很高兴的看到这个项目已经成为一个交流的平台，能让人们共同推进Qt。</p>

<p><span id="more-896"></span></p>

<p>此次Qt 5 Alpha发布的主要目的是获取反馈以帮助我们改进以后的发布。对于Alpha版，我们着重于Qt Essential模块，这些模块构成了Qt5提供的功能的基础。。</p>

<p>Alpha版本可以在<a href="http://qt-project.org/wiki/Qt-5-Alpha">http://qt-project.org/wiki/Qt-5-Alpha</a>下载。请注意此alpha版只以源码形式的发布，没有可供下载的二进制版本，所以您得自己编译二进制文件。编译介绍参见<a href="http://qt-project.org/wiki/Qt-5-Alpha-building-instructions">http://qt-project.org/wiki/Qt-5-Alpha-building-instructions</a></p>

<p>自从去年5月我在一篇<a href="http://labs.qt.nokia.com/2011/05/09/thoughts-about-qt-5/">博客</a>中概述了这个想法以来，我们已经在Qt 5上工作了差不多9个月了。那篇博客讲了我们在Qt 5中的几个目标，现在我想稍微反映些我们已经实现的部分。</p>

<h2>理念</h2>

<p>有一个基础的理念引领了大部分的Qt 5开发工作：</p>

<p><em>”Qt 5应当成为全新应用开发方式的基础。 一方面使用C++提供本地化Qt的全部能力，同时重点应当转移到一个模型上，这个模型使C++主要被用来实现Qt Quick模块化的后台功能。“</em></p>

<p>我要说的是我们在Qt 5上有一个好方法向着这个理念靠近。这个模型在那些UI是全屏的嵌入式Qt上工作良好。对于桌面环境，我们已经针对所需的这个模型打下了许多基础，但是我们在5.1或者5.2发布的时候才能确切地让这个模型可用。</p>

<h2>开放的开发</h2>

<p>我们希望在开放中开发Qt 5，围绕着一个强健的社区。自推出<a href="http://qt-project.org/">qt-project.org</a>以来，我们看见了一个充满活力的社区，并且我们在Qt 5中的许多补丁与新特性都是由社区提供的。</p>

<h2>架构的四大变化</h2>

<p>我们已经着手对四个主要的Qt内部架构进行修改：</p>

<ol>
<li><p><strong>把全部的Qt接口迁移到Qt Platform Abstraction(QPA)层之上 —— 使得Qt能更容易移植到另外的视窗系统和设备上</strong></p>

<p>使用<a href="http://qt-project.org/wiki/Qt-Platform-Abstraction">QPA</a>，我们从根本上改变了Qt如何集成相关操作系统的视窗环境。QPA在Qt 4.8中作为QWS/Qt嵌入式的一种替代引入，但是现在完全使用在所有平台上。这个迁移带来了大量的工作并且迫使我们重写了很大一部分的纯平台相关的代码。但是它也帮助我们创造了一个更干净的架构，使得平台依赖代码能够得到很好的抽象。可以看到，新的抽象化能显著地简化对于新视窗系统的集成工作，并且为QNX，Android和IOS编写的后台证明了这点。</p></li>
<li><p><strong>重新设计了图形堆栈 &#8211; 与Qt 4相比提高了性能，使用Qt Quick和OpenGL (ES) 2.0</strong></p>

<p>Qt 5为Qt Quick引入了全新的图形架构，使用了基于OpenGL的场景图（Scenegraph）。最低需求：OpenGL (ES) 2.0。QtGui现在包含了一组QOpenGL&#42;类，用以替代老的QGL&#42;类（为了兼容性这些类仍然可以使用）。我们还引入了一个比QApplication更轻量级的新类QGuiApplication和一个处理屏幕上顶层窗口的类QWindow。以QWidget为基础的那些类仍然像Qt 4.x一样工作，基于QPainter。然后QPainter比起以前支持更少的后端。它现在限制了于使用软件光栅（Raster bankend）来绘制屏幕、像素与图像，一个OpenGL后端提供GL接口以及一个提供PDF生成与打印的后端。平台依赖的后端比如X11或者CoreGraphics已经去掉了。这使得我们可以引入新的长期支持的图形架构的同时保证Qt 4.x的QWidget部分的完整兼容性。</p></li>
<li><p><strong>更加灵活的模块化库结构，满足桌面和移动的融合 &#8211; 按照需要添加或删除用户特定的模块，Qt mobility API的完整实现</strong></p>

<p>这主要是一些内部的清扫工作，一般不会被Qt开发者们直接看到。但是模块化Qt库使得我们能够更容易更独立的推进Qt的不同部分。这在Qt 5稳定过程以及我们发布Qt5.0开始保持二进制兼容性的时候显得日益重要。模块化的工作还没有完全搞定，特别是qtbase库仍然包含了很多需要被拆分的模块。所以这部分工作很可能在5.0出来之后还会继续。Qt的模块化还使得从第三方模块到Qt的集成容易了很多。它同样能很好地响应来自笔记本、平板和手机的不同需求趋势，比如有关手机特殊特性的地点、传感器等需求。Qt 5中我们能看到Qt mobility API集成进了Qt —— 其中部分API是一组被称为“Qt Essentials”模块的一部分。提供了这些模块之后，其它的模块就能以简单方式加入了。我们现在已经确认Qt5能比以往任何Qt版本提供更丰富的功能特性清单。请注意此alpha版本就是重点关注Qt Essentials。</p></li>
<li><p><strong>拆分全部QWidget相关的功能到其自有的类库</strong></p>

<p>通过拆分QWidget到独立的库中，我们不但确保了那些喜欢QWidgets的朋友可以继续使用它们，也为全部使用QML和Qt Quick的UI模型提供了途径。拆分QWidget为基础的功能到其自有的类当中是达到一个长期保持Qt 5架构干净的一个衡量之后的好措施。</p></li>
</ol>

<p>这些改变的发表带来了许多反馈，早前我们已经<a href="http://labs.qt.nokia.com/2011/05/11/responses-to-qt-5/">给出了</a>关于Qt 5和架构改变产生的一些常见问题。</p>

<h2>新功能</h2>

<p>除了架构的改变之外，Qt 5同样提供了许多新功能。在这里我突出介绍其中的一部分，详细的清单在我们的<a href="http://qt-project.org/wiki/Qt-5Features">wiki</a>中有描述。</p>

<ul>
<li><strong>Qt Core</strong></li>
</ul>

<p>QtCore已添加了许多新特性。现在有一个QStandardPaths类来提供对应平台的媒体、文档之类的标准位置。Core还包含了一个以二进制进行速度优化的JSON解析器。我们引入了对插件形式和文件内容的Mime类型的识别。Core同时还加入了一种新的可以在编译时检查信号/槽的连接的语法，以及一个完整的新的Perl兼容的正则表达式引擎。我们重写与优化了许多数据结构以获得更好的性能。我们也有意义的加入了C++11的支持，同时Qt也能继续在C++98兼容的编译器上编译运行。</p>

<ul>
<li><strong>Qt Gui</strong></li>
</ul>

<p>所有基于QWidget的类都被拆分到了QtWidgets库中。QtGui通过QWindow类获得了顶层界面的支持，同时现在有了内置的OpenGL支持。</p>

<ul>
<li><strong>Qt Network</strong></li>
</ul>

<p>我们加入了对DNS查找的支持并移除了QHttp和QFtp类（对那些还需要使用它们的人来说这些类可以独立使用）。还有许多和上面提到的类似的优化。</p>

<ul>
<li><strong>Qt Widgets</strong></li>
</ul>

<p>移植到了新的QPA架构之上而且可以像在Qt 4.x时那样使用。</p>

<ul>
<li><strong>Qt Quick</strong></li>
</ul>

<p>来自Qt 4.x时代的Qt Quick现在也完美兼容并叫做Qt Quick 1模块。这个模块已经完成不会再得到任何更新了。现在这部分的焦点是新的Qt Quick和Qt Qml模块。Qt 5中我们把Qt Quick的图像部分从QML和JS语法中拆分到不同模块了。新的JS类（QJSEngine和QJSValue）现在使用Google的V8引擎作为场景的后台，提供了更好的JavaScript性能。Qt Quick模块包含了基于OpenGL的场景图和在Qt 4.x就有了的全部基础项。我们加入了对基于GL的阴影、粒子和其它许多特效的支持。在QML侧大部分东西都是源码兼容的，但是如果用C++写的QML项则需要一些修改来适应这个新的场景图。</p>

<ul>
<li><strong>Qt 3D and Qt Location</strong></li>
</ul>

<p>一些额外的模块加入到了Qt Essentials组中，其中值得一提的是Qt 3D用来整合Qt和3D内容，和Qt Location用来提供GPS访问，地图和其它基于地址的服务。</p>

<ul>
<li><strong>Qt Webkit</strong></li>
</ul>

<p>自Qt 4.x以来Webkit的C++ API就没有变化过，但是Qt Webkit得到了来自webkit.org的版本更新，带给了我们许多性能的提高以及更好的HTML 5支持。这次的alpha版本在Windows关闭了这个选项，因为目前的编译工作还稍显复杂。我们正在努力工作，以确保在Beta版本中能重启这个功能并正常工作。</p>

<h2>从Qt 4.x 到Qt 5的迁移</h2>

<p>在Qt 4.x与Qt 5之间有少量的二进制以及源码兼容性差异。但是我们努力调整使得能够简单平滑的把现有代码过渡到Qt 5支持的形式。一个例子就是目前我们有Qt Creator，它用同样的代码编译在Qt 4.x和Qt 5之上。</p>

<p>如果您想在您的项目上尝试Qt 5，您可以在<a href="http://wiki.qt-project.org/Transition_from_Qt_4.x_to_Qt5">这里</a>查看详细的迁移指导手册。</p>

<p>同时也请注意没有必要现在就直接把您的程序迁移到Qt 5，Qt 4.8仍然被社区以及Digia这样的公司所支持。但是我们深信Qt 5有足够的好处值得让您迁移。</p>

<h2>下一步</h2>

<p>可以看到自从Qt 5.0开始发展以来已经发生了很多东西。我为我们目前的成就感到高兴。您现在就可以开始下载alpha，试用它并给予反馈来帮助我们完善Qt 5。</p>

<p>所有的反馈应当发在qt开发人员列表（development@qt-project.org, 参见<a href="http://lists.qt-project.org/mailman/listinfo/development">lists.qt-project.org</a>）或者简单地在我们的<a href="http://bugreports.qt-project.org/">bug跟踪系统</a>中提交一个bug。当然非常欢迎任意的补丁和bug修复，请提交到<a href="http://codereview.qt-project.org/">codereview.qt-project.org</a>。</p>

<p>Alpha版本是迈向Qt 5最终发布的第一步，从现在起重点就在解决剩下的问题以便我们能尽快交付一个最终的Qt 5.0出来。</p>

<p>为了达到这一点已经有很多的人参与进来了，但是我想说的是，感谢每一位对这个发布做出贡献的人。</p>

<p>Enjoy!</p>

<p>Lars</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qt.nokia.com.cn/2012/04/16/qt-5-alpha/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
