﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-简单为美-随笔分类-程序开发</title><link>http://www.cppblog.com/len/category/15381.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 05 Nov 2010 15:58:39 GMT</lastBuildDate><pubDate>Fri, 05 Nov 2010 15:58:39 GMT</pubDate><ttl>60</ttl><item><title>Python类、模块、包</title><link>http://www.cppblog.com/len/archive/2008/07/24/57078.html</link><dc:creator>len</dc:creator><author>len</author><pubDate>Thu, 24 Jul 2008 11:42:00 GMT</pubDate><guid>http://www.cppblog.com/len/archive/2008/07/24/57078.html</guid><wfw:comment>http://www.cppblog.com/len/comments/57078.html</wfw:comment><comments>http://www.cppblog.com/len/archive/2008/07/24/57078.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/len/comments/commentRss/57078.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/len/services/trackbacks/57078.html</trackback:ping><description><![CDATA[<p>Python在处理功能复用和功能颗粒度划分时采用了类、模块、包的结构。这种处理跟C++中的类和名字空间类似，但更接近于Java所采用的概念。</p>  <h3>类</h3>  <p>类的概念在许多语言中出现，很容易理解。它将数据和操作进行封装，以便将来的复用。</p>  <h3>模块</h3>  <p>模块，在Python可理解为对应于一个文件。在创建了一个脚本文件后，定义了某些函数和变量。你在其他需要这些功能的文件中，导入这模块，就可重用这些函数和变量。一般用<em>module_name.fun_name</em>，和<em>module_name.var_name</em>进行使用。这样的语义用法使模块看起来很像类或者名字空间，可将<em>module_name</em> 理解为名字限定符。模块名就是文件名去掉.py后缀。下面演示了一个简单的例子：</p>  <pre class="code">#moduel1.py
def say(word):
    print word

#caller.py
import module1

print __name__
print module1.__name__
module1.say('hello')</pre>

<pre class="console">$ python caller.py
__main__
module1
hello</pre>

<p>例子中演示了从文件中调用模块的方法。这里还展示了一个有趣的模块属性<em>__name__</em>，它的值由Python解释器设定。如果脚本文件是作为主程序调用，其值就设为__main__，如果是作为模块被其他文件导入，它的值就是其文件名。这个属性非常有用，常可用来进行模块内置测试使用，你会经常在一些地方看到类似于下面的写法，这些语句只在作为主程序调用时才被执行。</p>

<pre class="code">if __name__ == '__main__':
    app = wxapp(0)
    app.MainLoop()</pre>

<h4>模块搜索路径</h4>

<p>上面的例子中，当<em>module1</em>被导入后，python解释器就在当前目录下寻找module1.py的文件，然后再从环境变量<a>PYTHONPATH</a>寻找，如果这环境变量没有设定，也不要紧，解释器还会在安装预先设定的的一些目录寻找。这就是在导入下面这些标准模块，一切美好事情能发生的原因。</p>

<pre class="code">import os
import sys
import threading
...</pre>

<p>这些搜索目录可在运行时动态改变，比如将module1.py不放在当前目录，而放在一个冷僻的角落里。这里你就需要通过某种途径，如sys.path，来告知Python了。sys.path返回的是模块搜索列表，通过前后的输出对比和代码，应能理悟到如何增加新路径的方法了吧。非常简单，就是使用list的append()或insert()增加新的目录。</p>

<pre class="code">#module2.py
import sys
import os

print sys.path
workpath = os.path.dirname(os.path.abspath(sys.argv[0]))
sys.path.insert(0, os.path.join(workpath, 'modules'))
print sys.path</pre>

<pre class="console">$ python module2.py
['e:\\Project\\Python', 'C:\\WINDOWS\\system32\\python25.zip', ...]
['e:\\Project\\Python\\modules', 'e:\\Project\\Python', 'C:\\WINDOWS\\system32\\python25.zip', ...]</pre>

<h4>其他的要点</h4>

<p>模块能像包含函数定义一样，可包含一些可执行语句。这些可执行语句通常用来进行模块的初始化工作。这些语句只在模块第一次被导入时被执行。这非常重要，有些人以为这些语句会多次导入多次执行，其实不然。</p>

<p>模块在被导入执行时，python解释器为加快程序的启动速度，会在与模块文件同一目录下生成.pyc文件。我们知道python是解释性的脚本语言，而.pyc是经过编译后的字节码，这一工作会自动完成，而无需程序员手动执行。</p>

<h3>包</h3>

<p>在创建许许多多模块后，我们可能希望将某些功能相近的文件组织在同一文件夹下，这里就需要运用包的概念了。包对应于文件夹，使用包的方式跟模块也类似，唯一需要注意的是，当文件夹当作包使用时，文件夹需要包含__init__.py文件，主要是为了避免将文件夹名当作普通的字符串。__init__.py的内容可以为空，一般用来进行包的某些初始化工作或者设置__all__值，__all__是在<em>from package-name import *</em>这语句使用的，全部导出定义过的模块。</p><img src ="http://www.cppblog.com/len/aggbug/57078.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/len/" target="_blank">len</a> 2008-07-24 19:42 <a href="http://www.cppblog.com/len/archive/2008/07/24/57078.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>wxPython和XRC文件实现i18n</title><link>http://www.cppblog.com/len/archive/2008/07/15/56229.html</link><dc:creator>len</dc:creator><author>len</author><pubDate>Tue, 15 Jul 2008 12:21:00 GMT</pubDate><guid>http://www.cppblog.com/len/archive/2008/07/15/56229.html</guid><wfw:comment>http://www.cppblog.com/len/comments/56229.html</wfw:comment><comments>http://www.cppblog.com/len/archive/2008/07/15/56229.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/len/comments/commentRss/56229.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/len/services/trackbacks/56229.html</trackback:ping><description><![CDATA[
		<p>应用程序国际化，在开源世界里常以i18n被提及，i18n是Internationalization的简写，正好18个字母。在wxPython程序进行i18n，如果字符串是编码在源文件中时，完全可按照python程序的i18n的方法，即使用gexttext和locale模块。而wxPython程序在使用XRC文件做为界面资源时，则应使用wx.Locale模块，它封装了区域化相关的操作。i18n，或者国际化实际上涉及到语言习惯，数字格式等等类别的内容。这里只介绍语言多国化，将一个简单的英文程序转换为中文，涉及到源文件，可从<a href="/Files/len/wx.zip">这里</a>下载。</p>
		<h3>创建PO文件</h3>
		<p>PO文件是Portable Object文件的简称，它包含需要翻译的字符串。我们需要从源文件进行提取。首先，对源文件test.py编辑，标识代码里需要翻译的字符串内容。我们使用_("xx")的方法，这种形式可能在许多开源源代码中见识过。</p>
		<pre class="code">#加载菜单栏
menubar = rc.LoadMenuBar('IDR_MENU')</pre>
		<p>这里的IDR_MENU是资源标识ID，不需要翻译，因此不做改变，而下面的代码：</p>
		<pre class="code">info.SetVersion('1.0')
info.SetDescription('XRC i18n Demo')</pre>
		<p>'XRC i18n Demo'是描述性的文本，需要进行翻译，将需要处理为</p>
		<pre class="code">info.SetVersion('1.0')
info.SetDescription(_('XRC i18n Demo'))</pre>
		<p>接着需要生成.pot(Portable Object Template)，这是po的模板文件。在将来程序可能配置成其他语种，其他语言的po文件都从它而来。为了创建这文件，需要用到GNU gettext工具集中的xgettext。向xgettext传入些必要的信息，来创建.pot文件。</p>
		<pre class="console">&gt;xgetttext --output=test.pot test.py</pre>
		<p>我们将wxPython界面以XRC文件保存了，那里同样有要翻译的字符串需要提取。用XRCed工具将XRC生成python代码，勾选上'Generate gettext strings'项即可。将源文件和XRC生成的test_xrc.py文件一起处理，生成一个test.pot。</p>
		<pre class="console">&gt;xgettext --output=test.pot test.py test_xrc.py</pre>
		<p>将得到的test.pot另存为test.po文件，然后进行翻译编辑，在这过程中文件需要使用utf-8编码。将对应的英文翻译成中文，将charset更改为utf-8。</p>
		<pre class="code">"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: test.py:19
msgid "XRC i18n Demo"
msgstr "XRC 国际化示例"
...</pre>
		<p>.pot和.po这些文件都是文本文件，主要供翻译者使用。为了使程序在运行时能获取相关的翻译的内容，要进行所谓的编译过程，将文本文件转换为二进制文件.mo。这里用了gettext工具集中的另一程序msgfmt。</p>
		<pre class="console">&gt; msgfmt --output=test.mo test.po</pre>
		<p>因为windows下没有像linux像有公共存储.mo文件的目录，保持平台的迁移性，在应用程序本地目录下新建locale目录，用来存放编译过的.mo文件，然后将test.mo移动至locale目录。在完成这些步骤后，就转入代码方面的更改了。</p>
		<h3>wxPython代码更改</h3>
		<p>原先的代码只需要做小改动：</p>
		<pre class="code">def OnInit(self):
    wx.Locale.AddCatalogLookupPathPrefix('locale')
    self.locale = wx.Locale(wx.LANGUAGE_CHINESE_SIMPLIFIED)
    self.locale.AddCatalog('test')
    import __builtin__
    __builtin__.__dict__['_'] = wx.GetTranslation</pre>
		<p>首先，增加了新的目录文件路径，这将使wxPython搜索这个目录，寻找匹配的.mo文件。接着创建wx.Locale对象，将其初始化为简体中文，这将对应于zh_CN。最后将wx.GetTranslation做了一全局映射，这样你在其他类中，比如示例中TestFrame也能使用_('xx')调用。这样wxPython的i18n工作就完成了，下面是翻译前后的界面截图。</p>
		<p>
				<a href="/images/cppblog_com/len/WindowsLiveWriter/wxPythonXRCi18n_10874/wxpython_2.png">
						<img style="border-width: 0px;" alt="wxpython" src="http://www.cppblog.com/images/cppblog_com/len/WindowsLiveWriter/wxPythonXRCi18n_10874/wxpython_thumb.png" border="0" height="400" width="644" />
				</a>
		</p>
		<h3>一些有益的讨论</h3>
		<h4>.mo文件的查找目录</h4>
		<p>如果你将locale目录下的test.mo文件删除掉，然后将test.py中的wx.LANGUAGE_CHINESE_SIMPLIFIED改为wx.LANGUAGE_CHINESE，重新运行程序看看。发现界面变成了如下的繁体中文，但是菜单'档案'下的Exit还是英文。</p>
		<p>
				<a href="/images/cppblog_com/len/WindowsLiveWriter/wxPythonXRCi18n_10874/wxzh_2.png">
						<img style="border-width: 0px;" alt="wxzh" src="http://www.cppblog.com/images/cppblog_com/len/WindowsLiveWriter/wxPythonXRCi18n_10874/wxzh_thumb.png" border="0" height="77" width="404" />
				</a>
		</p>
		<p>因为缺失.mo文件，但又指定wx.LANGUAGE_CHINESE，wxPython运行时使用了wxstd.mo文件。wxstd.mo有许多预编译好的常见字符串的对应关系，它随wxPython发布，在wx/locale下有许多语言版本的wxstd.mo。</p>
		<p>对于wxPython会对待查目录"DIR"来搜索.mo文件，查找它下面的这些目录,(DIR/LANG/LC_MESSAGES;DIR/LANG;DIR),对于哪些是待查目录，各个系统下又有不同，在所有的平台上,LC_PATH环境变量指定的目录将成为待查目录，在Linux下/share/locale, /usr/share/locale, /usr/lib/locale, /usr/locale /share/locale以及当前目录将是待查目录。在上面我们已经用过AddCatalogLookupPathPrefix()函数，其作用就是增加自己的待查目录。</p>
		<p>在示例程序中，将test.mo放在locale\zh_CN\LC_MESSAGES或者locale\zh\LC_MESSAGES同样是可行的。但是如果使用wx.LANGUAGE_CHINESE指定，则zh_CN目录将不可行，因为它只是特化目录，指简体中文，而zh目录同样适用。</p>
		<h4>工具链再讨论</h4>
		<p>gettext进行国际化是开源社区的主流方案，它也提供了许多实用工具供使用。上面提到了xgettext,msgfmt，还有msginit.exe，它将根据.pot文件创建新的.po文件，然后初始化一些元信息，像作者信息，项目，以及编码等，当然也可像上面的手工编辑。msgmerge.exe将两个.po文件进行合并。除了使用GNU Gettext工具集，也可使用随python发布的tool\i18n目录下pygettext.py和msgfmt.py，它们等同于上述的两个工具。</p>
		<p>对于编辑.po文件，可以尝试一下<a href="http://www.poedit.net/index.php">Poedit</a>,它提供了图形化的编辑环境，其他功能我就不清楚了。</p>
<img src ="http://www.cppblog.com/len/aggbug/56229.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/len/" target="_blank">len</a> 2008-07-15 20:21 <a href="http://www.cppblog.com/len/archive/2008/07/15/56229.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开发Windows Live Writer插件小记</title><link>http://www.cppblog.com/len/archive/2008/07/05/55423.html</link><dc:creator>len</dc:creator><author>len</author><pubDate>Sat, 05 Jul 2008 13:43:00 GMT</pubDate><guid>http://www.cppblog.com/len/archive/2008/07/05/55423.html</guid><wfw:comment>http://www.cppblog.com/len/comments/55423.html</wfw:comment><comments>http://www.cppblog.com/len/archive/2008/07/05/55423.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/len/comments/commentRss/55423.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/len/services/trackbacks/55423.html</trackback:ping><description><![CDATA[
		<p>Windows Live Writer是写博客的利器,非常好用。只是对一些常见的html标签支持不足，比如没有预排文本标签&lt;pre&gt;之类的。在插入示例代码时，我不喜欢使用网上的那些高亮插件，它们增加了一些我感觉不友好的标签元素。我在写文章时，代码放在&lt;pre&gt;标签，然后使用自定义的code类，如果是一些屏幕输入输入文本，会用一个console类来进行说明。如果直接从源代码拷贝文本至html源文件时，xml文件的的&lt;&gt;"之类标签需要进行转义才可以。在这之前，我都需要手工将WLW切换到HTML模式进行创作，然后修改这些标签，非常麻烦。这样干了几次后，昨天决定自己写个WLW插件用。在搜索引擎的帮助下，找到Dflying Chen的 <a href="http://www.cnblogs.com/dflying/archive/2006/12/03/580602.html">为Windows Live Writer开发插件——InsertSearchPageLink</a>这篇文章，并在其参照完成了插件编写。</p>
		<p>但在找到这篇文章之前，和编写插件的过程中，还是费了很多功夫。最早我认为写插件是需要下载SDK之类的软件，所以在<a href="http://dev.live.com/writer/">Live Writer官方开发网站</a>，Live Writer网，MSDN之类的找了个遍，看见是有SDK之类字样的下载，但弄不下来只有文档，根本不见其什么头文件，DLL之类的。在这花费了很多时间，最后才发现WLW插件的SDK是随WLW一起分发了，也就是WindowsLive.Writer.Api.dll之类的，这些dll 都随WLW主程序在一个目录中。还有一点是，现在WLW在中国是随Live套件一起发布的，因此路径由原来的C:\Program Files\Windows Live Writer变成了C:\Program Files\Windows Live\Writer，插件目录为Plugin。如果在网上发现有好用的插件，只需要将其发布的插件dll扔到这个目录就行了。</p>
		<p>在开发中碰到图标资源不能成功加载，在Dflying Chen的文章中特意提到了图标资源需要是嵌入形式，我也按照其操作的，总以为是这里出现问题。后来花了一些时间，才找到总是的根源：自己在开发中更改了工程名，导致最后生成的程序集的名称与后来的命名空间名称不一致，图标路径就出错了。C#也只是这次用一下，这些都没有接触到。</p>
		<p>昨天弄完自己的“插入Pre标记”插件后，想到自己写博客常需要截图，遂想再开发一个截图工具的。最早搜到了别人调用SnagIt搜件，不好用，因为SnagIt是商业软件，需要注册的。后来找到了<a href="http://eng.wiziple.net/">picpick</a>，小巧免费，非常实用。我想调用picpick的，但是在参照Insert SnagIt Screen Capture发现是用COM接口，而无奈picpick没有这样供开发使用的接口考虑，最终不可行。后来经过一些其他的尝试，都告失败。最后还是搜索帮了忙，找到了<a href="http://livesino.net/archives/879.live">Screen Capture</a>这个插件，原来有别人已完工了。</p>
		<p>最后附上，我用这个新插件截的图，非常好用，只需一步：</p>
		<p>
				<a href="/images/cppblog_com/len/WindowsLiveWriter/WindowsLiveWriter_124A7/tmp196_2.png">
						<img style="border: 0px none ;" alt="tmp196" src="http://www.cppblog.com/images/cppblog_com/len/WindowsLiveWriter/WindowsLiveWriter_124A7/tmp196_thumb.png" border="0" height="238" width="202" />
				</a>
		</p>
<img src ="http://www.cppblog.com/len/aggbug/55423.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/len/" target="_blank">len</a> 2008-07-05 21:43 <a href="http://www.cppblog.com/len/archive/2008/07/05/55423.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(翻译)Python标准库的threading.Thread类</title><link>http://www.cppblog.com/len/archive/2008/06/24/54472.html</link><dc:creator>len</dc:creator><author>len</author><pubDate>Tue, 24 Jun 2008 08:54:00 GMT</pubDate><guid>http://www.cppblog.com/len/archive/2008/06/24/54472.html</guid><wfw:comment>http://www.cppblog.com/len/comments/54472.html</wfw:comment><comments>http://www.cppblog.com/len/archive/2008/06/24/54472.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/len/comments/commentRss/54472.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/len/services/trackbacks/54472.html</trackback:ping><description><![CDATA[
		<p>这个类表示在单独的控制线程中运行的活动。有两种方法可以指定这种活动，给构造函数传递回调对象，或者在子类中重写<tt>run() </tt>方法。其他方法（除了构造函数)都不应在子类中被重写。换句话说，在子类中只有<tt>__init__()</tt>和<tt>run()</tt>方法被重写。 </p>
		<p>一旦线程对象被创建，它的活动需要通过调用线程的start()方法来启动。这方法再调用控制线程中的run方法。 </p>
		<p>一旦线程被激活，则这线程被认为是'alive'(活动)。当它的run()方法终止时-正常退出或抛出未处理的异常，则活动状态停止。<tt>isAlive()</tt>方法测试线程是否是活动的。 </p>
		<p>一个线程能调用别的线程的<tt>join()</tt>方法。这将阻塞调用线程，直到拥有<tt>join()</tt>方法的线程的调用终止。 </p>
		<p>线程有名字。名字能传给构造函数，通过<tt>setName()</tt>方法设置，用<tt>getName()</tt>方法获取。 </p>
		<p>线程能被标识为'daemon thread'(守护线程).这标志的特点是当剩下的全是守护线程时，则Python程序退出。它的初始值继承于创建线程。这标志用<tt>setDaemon()</tt>方法设置，用<tt>isDaemon()</tt>获取。 </p>
		<p>存在'main thread'(主线程),它对应于Python程序的初始控制线程。它不是后台线程。 </p>
		<p>有可能存在'dummy thread objects'(哑线程对象)被创建。这些线程对应于'alien threads'(外部线程),它们在Python的线程模型之外被启动，像直接从C语言代码中启动。哑线程对象只有有限的功能，它们总是被认为是活动的，守护线程，不能使用<tt>join()</tt>方法。它们从不能被删除，既然它无法监测到外部线程的中止。</p>
		<dl>
				<dt>
						<tt>class Thread(<var>group=None, target=None, name=None, args=(), kwargs={}</var>)</tt>
				</dt>
				<dd>
						<p>构造函数能带有关键字参数被调用。这些参数是:</p>
						<p>
								<var>group</var> 应当为 None，为将来实现<tt>ThreadGroup</tt>类的扩展而保留。</p>
						<p>
								<var>target</var> 是被 <tt>run()</tt>方法调用的回调对象. 默认应为None, 意味着没有对象被调用。</p>
						<p>
								<var>name</var> 为线程名字。默认，形式为'Thread-<var>N</var>'的唯一的名字被创建，其中<var>N</var> 是比较小的十进制数。</p>
						<p>
								<var>args</var>是目标调用参数的tuple，默认为()。</p>
						<p>
								<var>kwargs</var>是目标调用的参数的关键字dictionary，默认为{}。</p>
						<p>如果子线程重写了构造函数，它应保证调用基类的构造函数<tt>(Thread.__init__())</tt>，在线程中进行其他工作之前。</p>
				</dd>
				<dt>
						<tt>start()</tt>
				</dt>
				<dd>启动线程活动。 
<p>在每个线程对象中最多被调用一次。它安排对象的<tt>run()</tt> 被调用在一单独的控制线程中。</p></dd>
				<dt>
				</dt>
				<p>
						<tt>run()</tt>
				</p>
				<dd>用以表示线程活动的方法。
</dd>
				<dd>
						<p>你可能在子类重写这方法。标准的 <tt>run()</tt>方法调用作为<var>target</var>传递给对象构造函数的回调对象。如果存在参数，一系列关键字参数从<var>args</var>和<var>kwargs参数相应地起作用。</var></p>
				</dd>
				<dt>
						<tt>join([<var>timeout</var>])</tt>
				</dt>
				<dd>等待至线程中止。这阻塞调用线程直至线程的<tt>join()</tt> 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
</dd>
				<dd>
						<p>当<var>timeout</var>参数未被设置或者不是<code>None</code>,它应当是浮点数指明以秒计的操作超时值。因为<tt>join()</tt>总是返回<code>None</code>，你必须调用<tt>isAlive()</tt>来判别超时是否发生。</p>
				</dd>
				<dd>
						<p>当<var>timeout</var> 参数没有被指定或者是<code>None</code>时，操作将被阻塞直至线程中止。</p>
				</dd>
				<dd>
						<p>线程能被<tt>join()许多次。</tt></p>
				</dd>
				<dd>
						<p>线程不能调用自身的<tt>join()，因为这将会引起死锁。</tt></p>
				</dd>
				<dd>
						<p>在线程启动之前尝试调用<tt>join()</tt>会发生错误。</p>
				</dd>
				<dt>
						<tt>getName()</tt>
				</dt>
				<dd>返回线程名。 
</dd>
				<dt>
						<tt>setName(<var>name</var>)</tt>
				</dt>
				<dd>设置线程名。 
</dd>
				<dd>
						<p>这名字是只用来进行标识目的的字符串。它没有其他作用。多个线程可以取同一名字。最初的名字通过构造函数设置。 </p>
				</dd>
				<dt>
						<tt>isAlive()</tt>
				</dt>
				<dd>返回线程是否活动的。
</dd>
				<dd>
						<p>大致上，线程从 <tt>start()</tt>调用开始那点至它的<tt>run()</tt>方法中止返回时，都被认为是活动的。模块函数<tt>enumerate()返回活动线程的列表。</tt></p>
				</dd>
				<dt>
						<tt>isDaemon()</tt>
				</dt>
				<dd>返回线程的守护线程标志。
</dd>
				<dt>
						<tt>setDaemon(<var>daemonic</var>)</tt>
				</dt>
				<dd>设置守护线程标志为布尔值<var>daemonic</var>。它必须在<tt>start()</tt>调用之前被调用。
</dd>
				<dd>
						<p>初始值继承至创建线程。</p>
				</dd>
				<dd>
						<p>当没有活动的非守护线程时，整个Python程序退出。</p>
				</dd>
		</dl>
		<p>
				<strong>参见</strong>:<a href="http://docs.python.org/lib/thread-objects.html">Python Library Reference</a></p>
<img src ="http://www.cppblog.com/len/aggbug/54472.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/len/" target="_blank">len</a> 2008-06-24 16:54 <a href="http://www.cppblog.com/len/archive/2008/06/24/54472.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Boost.Program_options简述</title><link>http://www.cppblog.com/len/archive/2008/06/15/53368.html</link><dc:creator>len</dc:creator><author>len</author><pubDate>Sun, 15 Jun 2008 13:03:00 GMT</pubDate><guid>http://www.cppblog.com/len/archive/2008/06/15/53368.html</guid><wfw:comment>http://www.cppblog.com/len/comments/53368.html</wfw:comment><comments>http://www.cppblog.com/len/archive/2008/06/15/53368.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/len/comments/commentRss/53368.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/len/services/trackbacks/53368.html</trackback:ping><description><![CDATA[
		<h3>介绍</h3>
		<p>命令行接口是普遍,基础的人机交互接口，从命令行提取程序的运行时选项的方法有很多。你可以自己编写相对应的完整的解析函数，或许你有丰富的C语言编程经验，熟知getopt()函数的用法，又或许使用Python的你已经在使用optparse库来简化这一工作。大家在平时不断地谈及到“不要重复造轮子”，那就需要掌握一些顺手的库，这里介绍一种C++方式来解析命令行选项的方法，就是使用Boost.Program_options库。</p>
		<p>program_options提供程序员一种方便的命令行和配置文件进行程序选项设置的方法。使用program_options库而不是你自己动手写相关的解析代码，因为它更简单，声明程序选项的语法简洁，并且库自身也非常小。将选项值转换为适合的类型值的工作也都能自动完成。库有着完备的错误检查机制，如果自己手写解析代码时，就可能会错过对一些出错情况的检查了。最后，选项值不仅能从命令行获取，也能从配置文件，甚至于环境变量中提取，而这些选择不会增加明显的工作量。</p>
		<h3>示例说明</h3>
		<p>以下面简单的hello程序进行说明，默认打印hello world,如果传入-p选项，就会打印出人的姓名，另外通过传入-h选项，可以打印出帮助选项。略微看一眼代码文件和相应的屏幕输入输出，然后我们再一起来看看这些是如何发生的。</p>
		<pre class="code">//hello.cpp 
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;boost/program_options.hpp&gt;

using namespace std;
int main(int argc, char* argv[])
{
    using namespace boost::program_options;
    //声明需要的选项
    options_description desc("Allowed options");
    desc.add_options()
        ("help,h", "produce help message")
        ("person,p", value&lt;string&gt;()-&gt;default_value("world"), "who")
        ;

    variables_map vm;        
    store(parse_command_line(argc, argv, desc), vm);
    notify(vm);    

    if (vm.count("help")) {
        cout &lt;&lt; desc;
        return 0;
    }
    cout &lt;&lt; "Hello " &lt;&lt; vm["person"].as&lt;string&gt;() &lt;&lt; endl;
    return 0;
}
</pre>
		<p>下面是在Windows命令提示符窗口上的输入输出结果，其中"&gt;"表示提示符。</p>
		<pre class="console">&gt;hello 
Hello world

&gt;hello -h
Allowed options:
  -h [ --help ]                produce help message
  -p [ --person ] arg (=world) who

&gt;hello --person len
Hello len
</pre>
		<p>首先通过options_description类声明了需要的选项，<tt>add_options</tt>返回了定义了<tt>operator()</tt>的特殊的代理对象。这个调用看起来有点奇怪，其参数依次为选项名，选项值，以及选项的描述。注意到示例中的选项名为"help,h"，是因为声明了具有短选项名和长选项名的选项，这跟gnu程序的命令行具有一致性。当然你可以省略短选项名，但是这样就不能用命令选项简写了。第二个选项的声明，定义了选项值为<tt>string</tt>类型，其默认值为<tt>world.</tt></p>
		<p>接下来,声明了<tt>variables_map</tt>类的对象，它主要用来存储选项值，并且能储存任意类型的值。然后，<tt>store,parse_command_line和notify</tt>函数使<tt>vm</tt>能存储在命令行中发现的选项。</p>
		<p>最后我们就自由地使用这些选项了，<tt>variables_map</tt>类的使用就像使用<tt>std::map</tt>一样，除了它必须用<tt>as</tt>方法去获取值。如果as方法调用的指定类型与实际存储的类型不同，就会有异常抛出。</p>
		<p>具有编程的你可能有这样的经验，使用<tt>cl或gcc</tt>对源文件进行编译时，可直接将源文件名放置在命令行中，而无需什么选项字母，如<tt>gcc a.c</tt>之类的。prgram_options也能处理这种情况，在库中被称为"positional options"(位置选项),但这需要程序员的一点儿帮助才能完成。看下面的经过对应修改的代码，我们无需传入"-p"选项，就能可指定"person"选项值</p>
		<pre class="code">    positional_options_description p;
    p.add("person", -1);
    store(command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
</pre>
		<pre class="console">&gt;hello len
Hello len
</pre>
		<p>前面新增的两行是为了说明所有的位置选项都应被解释成"person"选项，这里还采用了<tt>command_line_parser</tt>类来解析命令行，而不是用parse_command_line函数。后者只是对前者类的简单封装，但是现在我们需要传入一些额外的信息，所以要使用类本身。</p>
		<h3>选项复合来源</h3>
		<p>一般来说，在命令行上指定所有选项，对用户来说是非常烦人的。如果有些选项要应用于每次运行，那该怎么办呢。我们当然希望能创建出带有些常用设置的选项文件，跟命令行一起应用于程序中。当然这一切需要将命令行与配置文件中的值结合起来。比如，在命令行中指定的某些选项值应该能覆盖配置文件中的对应值，或者将这些值组合起来。</p>
		<p>下面的代码段将选项通过文件读取，这文件是文本格式，可用"#"表示注释，格式如命令行中的参数一样，选项=值</p>
		<pre class="code">    ifstream ifs("config.cfg");
    store(parse_config_file(ifs,config),vm);
    notify(vm);
</pre>
		<h3>参考</h3>
		<p>
		</p>
		<p>
				<a title="boost.program_options lib document" href="http://www.boost.org/doc/libs/1_35_0/doc/html/program_options.html">Boost.prgram_options库文档</a>
		</p>
<img src ="http://www.cppblog.com/len/aggbug/53368.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/len/" target="_blank">len</a> 2008-06-15 21:03 <a href="http://www.cppblog.com/len/archive/2008/06/15/53368.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Boost.Lambda简述</title><link>http://www.cppblog.com/len/archive/2008/05/18/50286.html</link><dc:creator>len</dc:creator><author>len</author><pubDate>Sun, 18 May 2008 08:03:00 GMT</pubDate><guid>http://www.cppblog.com/len/archive/2008/05/18/50286.html</guid><wfw:comment>http://www.cppblog.com/len/comments/50286.html</wfw:comment><comments>http://www.cppblog.com/len/archive/2008/05/18/50286.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/len/comments/commentRss/50286.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/len/services/trackbacks/50286.html</trackback:ping><description><![CDATA[
		<h3>Boost.Lambda是什么?</h3>
		<p>Boost Lambda库是C++模板库,以C++语言实现了lambda抽象.Lambda这个术语来自函数编程语言和lambda闭包理论,lambda抽象实际上定义了匿名函数.了解过C#新引入的匿数函数特性或Lisp编程的人，对这些概念理解会有很大帮助.Lambda库设计的主要动机是为STL算法提供灵活方便的定义匿名函数对象的机制.这个Lambda库究竟是有什么用呢?代码胜千言!看下面将STL容器中的元素打印到标准输出上的代码.</p>
		<pre class="code">for_each(a.begin(), a.end(), std::cout &lt;&lt; _1 &lt;&lt; ' ');</pre>
		<p>
		</p>
		<p>表达式<tt>std::cout &lt;&lt; _1 &lt;&lt; ' '</tt>定义了一元函数对象.变量<tt>_1</tt>是函数的形参,是实参的占位符.每次for_each的迭代中,函数带着实际的参数被调用,实际参数取代了占位符,然后函数体里的内容被执行.Lambda库的核心就是让你能像上面所展示的那样,在STL算法的调用点,定义小的匿名函数对象. </p>
		<h3>Lambda库的安装</h3>
		<p>Lambda库只由头文件组成,这就意味着你不需要进行任何编译,连接,生成二进制库的动作,只需要boost库头文件路径包含进你的工程中即可使用.</p>
		<p>与现代的C++语言一样,在使用时你需要声明用到的名字空间,把下列的代码包含在你的源文件头:</p>
		<pre class="code">using namespace boost::lambda;</pre>
		<h3>Boost Lambda库的动机</h3>
		<p>在标准模板库STL成为标准C++的一部分后,典型的STL算法对容器中元素的操作大都是通过函数对象(<tt>function objects</tt>)完成的.这些函数作为实参传入STL算法.</p>任何C++中以函数调用语法被调用的对象都是函数对象.STL对某些常见情况预置了些函数对象.比如:<tt>plus,less,not1</tt>下面就是标准<tt>plus</tt>模板的一种可能实现: <pre class="code">template &lt;class T&gt; 
struct plus : public binary_function &lt;T, T, T&gt; {
  T operator()(const T&amp; i, const T&amp; j) const {
    return i + j; 
  }
};
</pre><p>基类<tt>binary_function&lt;T, T, T&gt;</tt>包含了参数和函数对象返回类型的类型定义,这样可使得函数对象可配接.</p><p></p>除了上面提到的基本的函数对象外,STL还包含了<tt>binder</tt>模板,将可配接的二元函数中的某个实参固定为常量值,来创建一个一元函数对象.比如: 
<p></p><pre class="code">class plus_1 {
  int _i;
public:
  plus_1(const int&amp; i) : _i(i) {}
  int operator()(const int&amp; j) { return _i + j; }
};
</pre><p>上面的代码显性地创建了一个函数对象,将其参数加1.这样的功能可用<tt>plus</tt>模板与binder模板(<tt>bind1st</tt>来等效地实现.举例来说,下面的两行表达式创建了一个函数对象,当它被调用时,将返回1与调用参数的和.</p><pre class="code">plus_1(1)
bind1st(plus&lt;int&gt;(), 1)
</pre><p><tt>plus&lt;int&gt;</tt>就是计算两个数之和的函数对象.<tt>bind1st</tt>使被调用的函数对象的第一个参数绑定到常量1.作为上面函数对象的使用示例,下面的代码就是将容器<tt>a</tt>中的元素加1后,输出到标准输出设备:</p><pre class="code">transform(a.begin(), a.end(), ostream_iterator&lt;int&gt;(cout),
          bind1st(plus&lt;int&gt;(), 1));
</pre><p></p>为了使binder更加通用,STL包含了适配器<tt>(adaptors)</tt>用于函数引用与指针,以及成员函数的配接. 
<p></p><p>所有这些工具都有一个目标,就是为了能在STL算法的调用点有可能指定一个匿名的函数,换句说,就是能够使部分代码片断作为参数传给调用算法函数.但是,标准库在这方面只做了部分工作.上面的例子说明用标准库工具进行匿名函数的定义还是很麻烦的.复杂的函数调用表达式,适配器,函数组合符都使理解变得困难.另外,在运用标准库这些方法时还有明显的限束.比如,标准C++98中的binder只允许二元函数的一个参数被绑定,而没有对3参数,4参数的绑定.这种情况在TR1实施后,引进了通用的binder后可能改善,对于使用MSVC的程序员,有兴趣还可以查看下微软针对VS2008发布的TR1增强包.</p><p>但是不管怎样,Lambda库提供了针对这些问题比较优雅的解决方法:</p><ul><li><p>对匿名函数以直观的语义进行创建,上面的例子可改写成:</p><pre class="code">transform(a.begin(), a.end(), ostream_iterator&lt;int&gt;(cout), 
          1 + _1);
</pre><p>更直观点:</p><pre class="code">for_each(a.begin(), a.end(), cout &lt;&lt; (1 + _1));
</pre></li><li><p>绝大部分对函数参数绑定的限制被去除,在实际C++代码中可以绑定任意的参数</p></li><li><p>分离的函数组合操作不再需要了,函数组合被隐性地支持.</p></li></ul><h3>Lambda表达式介绍</h3><p>Lambda表达在函数式编程语言中很常见.在不同语言中,它们的语法有着很大不同,但是lambda表达式的基本形式是:</p><pre class="code">lambda x<sub>1</sub>...x<sub>n</sub>.e</pre><p>lambda表达式定义了匿名函数,并由下列的元素组成</p><ul><li>函数的参数:x<sub>1</sub>...x<sub>n</sub></li><li>表达式e,以参数x<sub>1</sub>...x<sub>n</sub>的形式计算函数的值</li></ul><p>一个简单的lambda表达式的例子是:</p><pre class="code">(lambda x y.x+y) 2 3 = 2 + 3 = 5 </pre><p>在lambda表达式的C++版本中,表达式中x<sub>1</sub>...x<sub>n</sub>不需要,已预定义形式化的参数.在现在Boost.Lambda库中,存在三个这样的预定义的参数,叫做占位符:<tt>_1,_2,和_3</tt>.它们分别指代在lambda表达式中的第一,二,三个参数.比如,下面这样的lambda表达式:</p><pre class="code">lambda x y.x+y</pre><p>C++定义的形式将会是这样:</p><pre class="code">_1 + _2</pre><p>因此在C++中的lambda表达式没有语义上所谓的关键字.占位符作为运算符使用时就隐性地意味着运算符调用是个lambda表达式.但是只有在作为运算符调用才是这样.当Lambda表达式包含函数调用,控制结构,转换时就需要特殊的语法调用了.更为重要的是,作为函数调用是需封装成binder函数的形式.比如,下面这个lambda表达式:</p><pre class="code">lambda x y.foo(x,y)</pre><p>不应写成foo(_1,_2),对应的C++结构应如下:</p><pre class="code">bind(foo, _1, _2)</pre><p>对于这种表达式,更倾向于作为绑定表达式<tt>bind expressions</tt></p><p>lambda表达式定义了C++的函数对象,因此,对于函数调用的形式跟其他的函数对象一样,比如:<tt>(_1 + _2)(i, j)</tt>.</p><h3>性能</h3><p>性能,运行效率,总是C++程序员关心的话题.理论上,相对于手写循环代码,使用STL算法和Lambda函数对象的所有运行开销,可以通过编译优化消除掉.这种优化取决于编译器,实际中的编译器大都能做到.测试表明,性能会有下降,但是影响不大,对于代码的效率和简洁之间的权衡,只能由程序员自己做出判断了.</p><p>Lambda库的设计与实现中大量运用了模板技术,造成对于同一模板需要大量的递归实例化．这一因素可能使构建复杂逻辑的lambda表达式，不是一个非常理想的做法．因为编译这些表达式需要大量的内存，从而使编译时间变得非常慢，这在一些大型项目中会更加突出．还有在发生编误错误时，引发的大量错误信息，不能有效地指出真正错误之处．最后点，C++标准建议模板的嵌套层次不要超过17层来防止导致无限递归,而复杂的Lambda表达式模板会很容易超过这一限制．虽然大多数编译器允许更深层次的模板嵌套，但是通常需要显性地传入一个命令行参数才能做到．</p><h3>参考</h3><p>大多数内容是从<a href="http://www.boost.org/doc/libs/1_35_0/doc/html/lambda.html">Boost.Lambday库在线文档</a>参考翻译而成</p><img src ="http://www.cppblog.com/len/aggbug/50286.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/len/" target="_blank">len</a> 2008-05-18 16:03 <a href="http://www.cppblog.com/len/archive/2008/05/18/50286.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(翻译)设计Qt风格的C++的应用程序接口</title><link>http://www.cppblog.com/len/archive/2008/05/11/49563.html</link><dc:creator>len</dc:creator><author>len</author><pubDate>Sun, 11 May 2008 12:07:00 GMT</pubDate><guid>http://www.cppblog.com/len/archive/2008/05/11/49563.html</guid><wfw:comment>http://www.cppblog.com/len/comments/49563.html</wfw:comment><comments>http://www.cppblog.com/len/archive/2008/05/11/49563.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/len/comments/commentRss/49563.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/len/services/trackbacks/49563.html</trackback:ping><description><![CDATA[
		<p>
				<strong>"Designing Qt-Style C++ APIs" by Matthias Ettrich</strong>
		</p>
		<p>
				<a title="http://doc.trolltech.com/qq/qq13-apis.html" href="http://doc.trolltech.com/qq/qq13-apis.html">http://doc.trolltech.com/qq/qq13-apis.html</a>
				<br />
		</p>
		<p>
				<em>翻译这篇文章的目的不是让人了解Qt，而是让人试着学习点C++编程的软技能。我从原文中得到的一些风格上的体会，也希望你能从中有所收获.（译者注)</em>
				<br />
				<strong>我们在Trolltech做了大量研究来改进Qt开发体验.在这篇文章中,我将分享我们的一些成果,呈现我们在进行Qt 4设计时所使遵循的原现，并向你展示如何将它们应用到你的代码中．</strong>
		</p>
		<ul>
				<li>
						<a href="#sixcharacteristicsofgoodapis">优秀API的六个特性</a>
				</li>
				<li>
						<a href="#theconveniencetrap">方便性陷阱</a>
				</li>
				<li>
						<a href="#thebooleanparametertrap">布尔参数陷阱</a>
				</li>
				<li>
						<a href="#staticpolymorphism">静态多态</a>
				</li>
				<li>
						<a href="#theartofnaming%22">命名艺术</a>
				</li>
				<li>
						<a href="pointersorreferences">指针或引用?</a>
				</li>
				<li>
						<a href="#casestudyqprogressbar">案例分析:QProgressBar</a>
				</li>
				<li>
						<a href="#howtogetapisright">怎样写出正确的API</a>
				</li>
		</ul>
		<p>设计应用程序接口(APIs)是有难度的.它是像跟设计编程语言一样困难的艺术．要遵循许多不同的的原则，这些原则中的许多还彼此冲突.</p>
		<p>现今的计算机教育过多关注于算法和数据结构，很少去关注隐藏在程序设计语言和程序框架后面的那些设计原则．这使得程序员们面对日益重要的任务,创建可复用的组件,毫无准备.</p>
		<p>在面向对象语言出现前,通用的可复用的代码大都由库提供者而不是应用程序开发者来编写.在Qt世界中，这种情况已发生了很大的变化．在用Qt编程其实就是在写新的组件.典型的Qt应用程序都存在某些自定义的组件，在整个应用程序中被复用.相同的组件常常作为其他程序的一部分被开发出来．KDE,K桌面环境,甚至使用许多附加库，来进一步扩展Qt，实现许多额外的类.</p>
		<p>但是一个优秀,高效的C++ API究竟是怎样子呢?它的好坏取决于许多因素,比如说，手头上的任务和特定目标群体.优秀的API具有很多特性,它们的一些是普遍所要期望的,另一些是针对特定问题域的.</p>
		<a name="sixcharacteristicsofgoodapis">
		</a>
		<h3>优秀API的六个特性 </h3>
		<p>API对于程序员就相当于GUI对于最终用户.API中'P'代表程序员(Programmer)，而不是程序(Program)，强调这一点是为了说明API是让程序员使用的,程序员是人而不机器. </p>
		<p>我们认为APIs应当精简而完备,具有清晰简单的语义，直观,易记且应使代码具有可读性.</p>
		<ul>
				<li>
						<strong>精简性</strong>:精简的API具有尽可能少的类和公共成员.这使得理解，记忆，调试，更改API更加容易. 
</li>
				<li>
						<strong>完备性</strong>：完备的API意味着拥有应具有的期望功能.这可能使与API保持精简性相冲突.还有，如果成员函数放在不相匹配的类中，那么许多使用这个功能函数的潜在用户会找不到它． 
</li>
				<li>
						<strong>清晰简单的语义</strong>:正如与其他设计工作一样，你应该准守最小惊议原则.让通常的任务简单，罕见的任务应尽可能简单，但它不应成为重点.解决特定的问题．不要使解决方法具有普适作用，当它们不需要的时候. 
</li>
				<li>
						<strong>直观性</strong>:与计算机有关的其他事情一样，API应具有直观性.不同经历和背景会导致对哪些是直观，哪些不是直观的不同看法．如果对非专业的用户在不需要阅读文档下能立即使用API,或对这个API不了解的程序员能理解使用了API的代码，那么这API就是具有直观性. 
</li>
				<li>
						<strong>易记</strong>:为了使API容易记忆，使用一致且精准的命名规范.使用容易识别的模式和概念，避免使用缩写. 
</li>
				<li>
						<strong>能生成可读生代码</strong>:代码只写一遍，却要阅读许多遍(调试或更改).可读性的代码有时候可能需要多敲些字,但是从产品生命周期中可节省很多时间. </li>
		</ul>
		<p>最后，请记住：不同的用户使用API的不同部分.当简单地使用Qt类的实例可能有直观性，但这有可能使用户在阅读完有关文档后，才能尝试使用其中部分功能.</p>
		<a name="theconveniencetrap">
		</a>
		<h3>方便性陷阱</h3>
		<p>通常的误读是越少的代码越能使你达到编写更好的API这一目的.请记住，代码只写一遍，却要一遍又一遍地去理解阅读它.比如:</p>
		<pre class="code">QSlider *slider = new QSlider(12, 18, 3, 13, Qt::Vertical,
                                  0, "volume");
</pre>
		<p>
		</p>
		<p>可以会比下面的代码更难阅读(甚至于编写)</p>
		<p>
		</p>
		<pre class="code">QSlider *slider = new QSlider(Qt::Vertical);
slider-&gt;setRange(12, 18);
slider-&gt;setPageStep(3);
slider-&gt;setValue(13);
slider-&gt;setObjectName("volume");
</pre>
		<p>
		</p>
		<a name="thebooleanparametertrap">
		</a>
		<h3>布尔参数陷阱</h3>
		<p>布尔参数常常导致难以阅读的代码.特别地，增加某个bool参数到现存的函数一般都会是个错误的决定．在Qt中，传统的例子是<tt>repaint()</tt>,它带有一个可选的布尔参数，来指定背景是否删除(默认是删除)．这就导致了代码会像这样子:</p>
		<pre class="code">widget-&gt;repaint(false);</pre>
		<p>初学者可能会按字面义理解为,"不要重绘!"</p>
		<p>自然的想法是<tt>bool参数节省了一个函数,因此减少了代码的臃肿.事实上,这增加了代码的臃肿，有多少Qt用户真正知道下面这三行代码在做什么呢？</tt></p>
		<pre class="code">widget-&gt;repaint();
widget-&gt;repaint(true);
widget-&gt;repaint(false);
</pre>
		<p>好一点的API代码可能看起来像这样：</p>
		<pre class="code">widget-&gt;repaint();
widget-&gt;repaintWithoutErasing();
</pre>
		<p>在Qt 4中，我们解决这个问题的办法是，简单地去除掉不删除<tt>widget</tt>而进行重绘的可能性.Qt 4对双重缓冲的原生支持，会使这功能被废弃掉.</p>
		<p>这里有些例子：</p>
		<p>
		</p>
		<pre class="code">widget-&gt;setSizePolicy(QSizePolicy::Fixed,
                          QSizePolicy::Expanding, true);
textEdit-&gt;insert("Where's Waldo?", true, true, false);
QRegExp rx("moc_*.c??", false, true);
</pre>
		<p>显然的解决办法就是将<tt>bool</tt> 参数用枚举类型来替换.这就是我们在Qt 4中Qstring中的大小写敏感所做的,比较下面两个例子:</p>
		<pre class="code">str.replace("%USER%", user, false);               // Qt 3
str.replace("%USER%", user, Qt::CaseInsensitive); // Qt 4
</pre>
		<a name="staticpolymorphism">
		</a>
		<h3>静态多态 </h3>
		<p>相似的类应该有相似的API.在某种程度上,这能用继承来实现,也就是运用运行时多态机制.但是多态也能发生在设计时.比如,你将QListBox与QComboBox交换,QSlider与QSpinBox交换,你会发现API的相似性会使这种替换变得比较容易.这就是我们所谓的"静态多态". </p>
		<p>静态多态也能使记忆API和编程模式更加容易.因而,对一组相关类的相似API有时候比为每个类设计独特完美的API会更好. </p>
		<a name="theartofnaming">
		</a>
		<h3>命名艺术</h3>
		<p>命名有时候是设计API中最重要的事情了.某个类应叫什么名字,某个成员函数又应叫什么名字,都需要好好思考.  </p>
		<h4>通常的命名规则</h4>
		<p>有少许规则对所有类型的命名都适应.首先,正如我早先所提到的,不要用缩写．甚至对用"prev"代表"previous"这样明显的缩写也不会在长期中受益，因为用户必须记住哪些名字是缩写． </p>
		<p>如果连API自身都不能保持统一,事情自然会变得更坏．比如，Qt 3中有<tt>activatePreviousWindow()函数，也有<tt>fetchPrev()函数</tt>.坚持"没有缩写"这条规则，会使创建一致的API更加简单． </tt></p>
		<p>在设计类中，另一重要但是不明显的规则是尽量保持子类中名字的简洁易懂．在Qt 3中，这个原则并不总是被遵守．为了说明这一点，我们举下QToolButton的例子.如果你在Qt 3中对QToolButton调用call <tt>name()</tt>, <tt>caption()</tt>, <tt>text()</tt>, 或 <tt>textLabel()成员函数时，你希望会发生什么?那就在Qt设计器中试试QToolButton吧．</tt></p>
		<ul>
				<li>
						<tt>name</tt> 属性继承自QObject，用来在调试和测试中指代对象的内部名称． 
</li>
				<li>
						<tt>caption</tt> 属性继承自QWidget，指代窗体的标题．对于QToolButton没有什么意思，既然它们都是由父窗体创建的． 
</li>
				<li>
						<tt>text</tt> 属性继承自QButton，通常用于按钮中，除非useTextLabel为真． 
</li>
				<li>
						<tt>textLabel</tt> 属性 在QToolButton中声明，如果<tt>useTextLabel为真，则显示在按钮上．</tt></li>
		</ul>
		<p>为了可读性的关系，在Qt4中<tt>name</tt> 被称为<tt>objectName</tt> ,<tt>caption被称为<tt>windowTitle</tt>,在QToolButton中为了使<tt>text</tt>明晰，不再有<tt>textLabel属性.</tt></tt></p>
		<h4>命名类</h4>
		<p>不应为每个不同的类寻求完美的名字，而是将类进行分给．比如，在Qt 4中所有跟模型有关的视类的部件都用<tt>View</tt>后缀(QlistView,QTableView,QTreeView)，相应的基于部件的类用<tt>Widget</tt>后缀代替(QListWidget,QTableWidget,QTreeWidge). </p>
		<h4>枚举类型和值类型命名</h4>
		<p>当设计枚举时，我们应当记住C++中(不像Java或C#)，枚举值在使用时不带类型名.下面的例子说明了对枚举值取太一般化的名字的危害：</p>
		<pre class="code">namespace Qt
{
    enum Corner { TopLeft, BottomRight, ... };
    enum CaseSensitivity { Insensitive, Sensitive };
    ...
};
    
    tabWidget-&gt;setCornerWidget(widget, Qt::TopLeft);
    str.indexOf("$(QTDIR)", Qt::Insensitive);
</pre>
		<p>在上面这行中，<tt>Insensitive这个名字什么意思呢?为枚举类型命名具有指导的原则是最好在每个枚举值中重复枚举类型的名字．</tt></p>
		<pre class="code">namespace Qt
{
    enum Corner { TopLeftCorner, BottomRightCorner, ... };
    enum CaseSensitivity { CaseInsensitive,
                              CaseSensitive };
    ...
};
    
tabWidget-&gt;setCornerWidget(widget, Qt::TopLeftCorner);
str.indexOf("$(QTDIR)", Qt::CaseInsensitive);
    </pre>
		<p>但枚举值之间是一种"或"关系和被用作标志位时，传统的解决方法是将"或"结果存为<tt>int</tt>,这样做是类型不安全的.Qt 4提供了一模板类QFlags&lt;T&gt;，其中T是枚举类型.Qt为标志类型名称提供了便利，你能用<tt>Qt::Alignment</tt> 来代替QFlags&lt;Qt::AlignmentFlag&gt;. </p>
		<p>为了方便,我们给枚举类型单数形式的名称(只有当只含一个标志位时)，给"flags"类型复数形式的名称，比如：</p>
		<pre class="code">enum RectangleEdge { LeftEdge, RightEdge, ... };
typedef <a href="http://doc.trolltech.com/4.0/qflags.html">QFlags</a>&lt;RectangleEdge&gt; RectangleEdges;
    </pre>
		<p>在某些情况下,"flags"类型有单数形式的名称.在这种情况下，枚举类型以<tt>Flag</tt>后缀标识:</p>
		<pre class="code">enum AlignmentFlag { AlignLeft, AlignTop, ... };
typedef <a href="http://doc.trolltech.com/4.0/qflags.html">QFlags</a>&lt;AlignmentFlag&gt; Alignment;
</pre>
		<h4>函数和参数的命名</h4>
		<p>函数命名中的一条规则就是应能从它的名字清楚地看出函数是否着副作用.在Qt 3中,常函数QString::simplifyWhiteSpace()就违反了这规则.即然它返回QString,而不是像它的名字所表述的那样修改字符串. 在Qt 4中,这个函数被重命名为QString::simplified(). </p>
		<p>参数名对于程序员来说是重要的信息来源,即使它们不出现在调用API的代码中.既然现代的IDE会在程序员编码时显示这些参数，所以非常值得在头文件中给这些参数取恰当的名字，在文档中同样使用相同的名字 </p>
		<h4>给布尔型的getter,setter,属性的命名</h4>
		<p>给布尔型的getter,setter,属性取个恰当的名字总是特别困难．getter应该叫<tt>checked()</tt> 或者还是叫<tt>isChecked(),取<tt>scrollBarsEnabled()</tt>还是<tt>areScrollBarEnabled()</tt></tt></p>
		<p>在Qt 4中，我们对于getter的函数使用下面的指导原则 </p>
		<ul>
				<li>形容词就使用<tt>is</tt>-前缀.比如: 
<ul><li><tt>isChecked()</tt></li><li><tt>isDown()</tt></li><li><tt>isEmpty()</tt></li><li><tt>isMovingEnabled()</tt></li></ul>但是形容词应用到复数形式的名词没有前缀: 
<ul><li><tt>scrollBarsEnabled()</tt>, not <tt>areScrollBarsEnabled()</tt></li></ul></li>
				<li>动词没有前缀，也不使用第三人称的(-s): 
<ul><li><tt>acceptDrops()</tt>, not <tt>acceptsDrops()</tt></li><li><tt>allColumnsShowFocus()</tt></li></ul></li>
				<li>名词性的通常没有前缀: 
<ul><li>用<tt>autoCompletion()</tt>, 不用<tt>isAutoCompletion()</tt></li><li><tt>boundaryChecking()</tt></li></ul>有时候没有前缀会产生误导，在这种情就加上前缀<tt>is</tt>-: 
<ul><li><tt>isOpenGLAvailable()</tt>, not <tt>openGL()</tt></li><li><tt>isDialog()</tt>, not <tt>dialog()</tt></li></ul>(如果函数叫做dialog()，我们通常会认定它会返回QDialog*类型) </li>
		</ul>
		<p>setter的命名可以从这推知，只要去掉is前缀，在名字前面加set前缀就可以了.比如<tt>setDown()</tt>和<tt>setScrollBarsEnabled().属性的名字跟getter一样，就是没有is前缀</tt></p>
		<a name="pointersorreferences">
		</a>
		<h3>指针或引用?</h3>
		<p>对于向外传参,是使用指针,还是引用更好呢? </p>
		<pre class="code">void getHsv(int *h, int *s, int *v) const
void getHsv(int &amp;h, int &amp;s, int &amp;v) const
</pre>
		<p>绝大多数C++书籍都推荐无论何时都尽可能使用引用，因为从大多数情况来说，引用比指针有着所谓的"安全和优雅".相比而方，在Trolltech，我们更趋向于指针，因为它使用户代码更具可读性．比较下面的代码：</p>
		<pre class="code">color.getHsv(&amp;h, &amp;s, &amp;v);
color.getHsv(h, s, v);
</pre>
		<p>只有第一行代码能更清楚地说明h,s,v在函数被调用后，其值极有可能被修改. </p>
		<a name="casestudyqprogressbar">
		</a>
		<h3>案例分析：QProgressBar</h3>
		<p>为了在实际代码中说明这些概念，我们以QProgressBar在Qt3和Qt4中的比较进行研究.在Qt 3中:</p>
		<pre class="code">class QProgressBar : public QWidget
{
  ...
    public:
        int totalSteps() const;
        int progress() const;
    
        const QString &amp;progressString() const;
        bool percentageVisible() const;
        void setPercentageVisible(bool);
    
        void setCenterIndicator(bool on);
        bool centerIndicator() const;
    
        void setIndicatorFollowsStyle(bool);
        bool indicatorFollowsStyle() const;
    
    public slots:
        void reset();
        virtual void setTotalSteps(int totalSteps);
        virtual void setProgress(int progress);
        void setProgress(int progress, int totalSteps);
    
    protected:
        virtual bool setIndicator(QString &amp;progressStr,
                                  int progress,
                                  int totalSteps);
        ...
    };
    </pre>
		<p>
		</p>
		<p>对这个API进行改进的关键之处就是需要观察到Qt 4中QProgressBar与QAbstractSpinBox，以及它的子类,QSpinBox,QSlider,和QDial有着相似性.解决的办法呢?将其中的progress和totalSteps用minimun,maximum和value替换. </p>
		<p>增加<tt>valueChanged()</tt>的信号量.增加<tt>setRange()</tt>这一方便的函数. </p>
		<p>接下来需要到<tt>progressString</tt>, <tt>percentage</tt> 和<tt>indicator实际上都指代同一东西：显示在进度栏上的文本.通常这一文本是一百分数,但是它能被<tt>setIndicator()</tt>设置成任何值.这里是新的API:</tt></p>
		<pre class="code">virtual QString text() const;
void setTextVisible(bool visible);
bool isTextVisible() const;
</pre>
		<p>默认，这文本是百分比指示器.这可以用重新实现的<tt>text()进行改变．</tt></p>
		<p>
				<tt>在Qt 3中，setCenterIndicator()</tt> 和 <tt>setIndicatorFollowsStyle()是两个影响对齐方式的函数.它们现在都被一个高级的函数所取代,<tt>setAlignment()</tt>．</tt></p>
		<pre class="code">void setAlignment(Qt::Alignment alignment);
</pre>
		<p>如果程序员没有调用 <tt>setAlignment()</tt>,对齐是基于的样式决定的．对于Motif样式，文本显示在中间，而对于其他样式，文本是右对齐的． </p>
		<p>这里是改进过的QProgressBar:</p>
		<pre class="code">class QProgressBar : public QWidget32
{
        ...
    public:
        void setMinimum(int minimum);
        int minimum() const;
        void setMaximum(int maximum);
        int maximum() const;
        void setRange(int minimum, int maximum);
        int value() const;
    
        virtual QString text() const;
        void setTextVisible(bool visible);
        bool isTextVisible() const;
        Qt::Alignment alignment() const;
        void setAlignment(Qt::Alignment alignment);
    
    public slots:
        void reset();
        void setValue(int value);
    
    signals:
        void valueChanged(int value);
        ...
};</pre>
		<a name="howtogetapisright">
		</a>
		<h3>怎样写出正确的APIs</h3>
		<p>APIs需要质量保证．最早的版本一般都不是很好的，你必须测试它．通过调用这个API的代码作为测试事例，来验证代码具有可读性. </p>
		<p>另外的技巧包括让人在没有文档和类文档化(类的概述和函数说明)的情况下能够使用这个API. </p>
		<p>当你陷入麻烦中时，文档化也是好的办法找出一个合适的命名：试着为这些类，函数，枚举值标住文档，然后使用浮现在你脑中的第一个词汇.如果你找不到精准的名字去表述，那很有可能这个东西就不应存在．如果任何办法都失败了，而且你确信这个概念是有用的，那就发明一个新的名字吧．最后，不管怎么说,"widget", "event", "focus", and "buddy"这些词总会能用上一个.</p>
<img src ="http://www.cppblog.com/len/aggbug/49563.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/len/" target="_blank">len</a> 2008-05-11 20:07 <a href="http://www.cppblog.com/len/archive/2008/05/11/49563.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Say Hello to Glade</title><link>http://www.cppblog.com/len/archive/2008/03/27/45548.html</link><dc:creator>len</dc:creator><author>len</author><pubDate>Thu, 27 Mar 2008 12:49:00 GMT</pubDate><guid>http://www.cppblog.com/len/archive/2008/03/27/45548.html</guid><wfw:comment>http://www.cppblog.com/len/comments/45548.html</wfw:comment><comments>http://www.cppblog.com/len/archive/2008/03/27/45548.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/len/comments/commentRss/45548.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/len/services/trackbacks/45548.html</trackback:ping><description><![CDATA[
		<p>Glade是针对GTK+工具箱与GNOME桌面开发环境的快速图形界面开发工具.用Glade设计的用户接口以XML的文件形式保存,然后根据需要由程序通过libglade库文件来动态加载.因为使用了libglade库,Glade XML文件能够被C,C++,Java,Perl,Python,C#等等语言所支持.针对其他未涉及的语言的支持也是方便的.</p>
		<p>在网上可以见到某些关于Glade的教程,大都是关于Linux平台和Glade 2的,因为原先Glade作为快速开发工具,集成代码生成功能,生成C文件.所以常常有初学者对网上某些教程所提及的"generate"(生成代码)功能表示迷惑,在新版本的Glade-3上找不到对应的功能.</p>
		<p>新版本的Glade-3是对原先Glade代码的完全重写.一个显著的变化就是去除了代码生成功能.这样做是有原因的,即然代码生成功能不被提倡使用,而是更鼓励使用libglade功能.但是如果你真需要代码生成功能的话,它还是可以做为插件来提供的.另一个显著的不同是glade-3设计用来最大化使用GObject的自省机制(GObject introspection),来使外部工具箱和部件的控制,信号和属性的集成更加容易.</p>
		<p>如果看过<a href="/len/archive/2008/03/23/45190.html">Say Hello to GTK+</a>的话，可能感觉那样的窗体程序太简单了．那么现在让我们借助Glade弄点儿复杂一点儿的界面吧．首先来瞧瞧Glade长什么样,下图就是Glade在windows下的界面.左边的窗体的小部件选择器，相当于调色板．中间是主菜单，右边的是属性窗体．</p>
		<p>
				<a href="/images/cppblog_com/len/WindowsLiveWriter/SayHellotoGlade_13792/glade_win_6.jpg">
						<img style="border-width: 0px;" alt="glade_win" src="http://www.cppblog.com/images/cppblog_com/len/WindowsLiveWriter/SayHellotoGlade_13792/glade_win_thumb_2.jpg" border="0" height="474" width="644" />
				</a>
		</p>
		<p>现在开始创建一个类似于文本编辑器的图形界面．按照上图标注的顺序，依次添加window部件，vertical box部件,menu bar部件,text view部件和Status部件.vertical box设置三行，它是用来进行界面布局，分割空间用，这是gtk+设计与传统的windows UI设计很不同的地方．后三个部件是放置vertical box中的，最后设计完成图形如下．保存取名为win.glade.如果你感兴趣的话，可以用文件编辑器打开这个文件看看，正如所说的那样，它是一个xml格式的文本文件．</p>
		<p>
				<a href="/images/cppblog_com/len/WindowsLiveWriter/SayHellotoGlade_13792/win_2.jpg">
						<img style="border-width: 0px;" alt="win" src="http://www.cppblog.com/images/cppblog_com/len/WindowsLiveWriter/SayHellotoGlade_13792/win_thumb.jpg" border="0" height="204" width="319" />
				</a>
		</p>
		<p>现在我们设置相关的头文件和库文件，编辑一个glade.c文件，添加进以下的代码，运行看看，会出现如上图的对话框．虽然这个对话框什么都不干，但是通过Glade，我们能较为容易地设计界面，而不用通过gtk函数，一个一个将控件实现.</p>
		<pre class="code">#include &lt;gtk/gtk.h&gt;<br />#include &lt;glade/glade.h&gt;
int main(int argc, char* argv[])
{
	GladeXML        *gxml;
	GtkWidget       *window;

	gtk_init (&amp;argc, &amp;argv);
	gxml = glade_xml_new ("win.glade", NULL, NULL);
	window = glade_xml_get_widget (gxml, "hello");
	g_object_unref (G_OBJECT (gxml));
	gtk_widget_show (window);                
	gtk_main ();

	return 0;
}

</pre>
<img src ="http://www.cppblog.com/len/aggbug/45548.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/len/" target="_blank">len</a> 2008-03-27 20:49 <a href="http://www.cppblog.com/len/archive/2008/03/27/45548.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Say Hello to GTK+</title><link>http://www.cppblog.com/len/archive/2008/03/23/45190.html</link><dc:creator>len</dc:creator><author>len</author><pubDate>Sun, 23 Mar 2008 07:18:00 GMT</pubDate><guid>http://www.cppblog.com/len/archive/2008/03/23/45190.html</guid><wfw:comment>http://www.cppblog.com/len/comments/45190.html</wfw:comment><comments>http://www.cppblog.com/len/archive/2008/03/23/45190.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/len/comments/commentRss/45190.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/len/services/trackbacks/45190.html</trackback:ping><description><![CDATA[
		<p>Windows下的C++程序员在开发图形用户界面时,首先想到可能就是MFC了.对于<a href="http://www.gtk.org/">GTK+</a>这种GNU/Linux上出生出来的东西,就感到陌生了．GTK+是类似于MFC的图形界面库,跟MFC不同的是,它不是用C++,而是用C语言实现了面对对象的机制,但能与许多语言绑定,并具有跨平台的特性.比如与<a href="http://www.python.org/">Python</a>的结合,就产生<a href="http://www.pygtk.org/">PyGTK</a>,"<a href="/len/archive/2008/03/12/44296.html">初识PyGTK"</a>就介结了其在Windows平台的安装.</p>
		<p>在Windows开发GTK+的应用程序,首先需要其在Windows版本下的库文件,下载<a href="http://sourceforge.net/projects/gladewin32">gladewin32</a>项目中的<a href="http://sourceforge.net/project/showfiles.php?group_id=98754&amp;package_id=111411">gtk+-win32-devel</a>安装包进行安装.我这里使用VS2005进行配置，因为相对于其他的环境，大家对于此IDE更为熟悉．接下来我将一步步介绍我在对GTK/Glande3说Hello时碰到的问题与解决方法．</p>
		<h3>丑陋的Hello World</h3>
		<p>任何像我一样急切的人，都希望用最少的代码，看一下GTK+的世界是怎么样的．新建一"Win32 项目",然后向其添加gtk.c文件.</p>
		<pre class="code">/*  file gtk.c  */ 
#include  &lt; gtk / gtk.h &gt; 

int  main( int  argc,  char *  argv[])
{
    GtkWidget *  window;
    gtk_init ( &amp; argc,  &amp; argv);

    window  =  gtk_window_new (GTK_WINDOW_TOPLEVEL);
    
    gtk_window_set_title (GTK_WINDOW (window),  " Hello World " );
    gtk_widget_show (window);
    gtk_main();

    return   0 ;
} 
</pre>
		<p>现在麻烦的事情到了,设置相关的头文件和库文件.设置头文件,右键点击项目名,然后选择属性.然后在"常规"-"附加包含目录"中设置你安装gtk+-win32-devel时对应的头文件目录.然后再设置库文件,需要gtk-win32-2.0.lib,glib-2.0.lib,gobject-2.0.lib.</p>
		<img alt="p1_4.jpg" src="http://www.cppblog.com/images/cppblog_com/len/WindowsLiveWriter/f5af5ed389e0_9458/p1_4.jpg" border="0" height="432" width="640" />
		<br />
		<img alt="p2_thumb.jpg" src="http://www.cppblog.com/images/cppblog_com/len/WindowsLiveWriter/f5af5ed389e0_9458/p2_thumb.jpg" border="0" height="234" width="340" />
		<img alt="p3_thumb.jpg" src="http://www.cppblog.com/images/cppblog_com/len/WindowsLiveWriter/f5af5ed389e0_9458/p3_thumb.jpg" border="0" height="234" width="318" />
		<p>设置完好后,你就可以编译运行了,一个什么都不干的丑陋的windows窗体出现你面前了.若编译不通过,缺少某些头文件的话,查看出错信息,然后用windows查找对应头文件路径,再设置.若连接出错,很可能在设置库文件出错了,同理,设置相应的库文件路径.程序代码很简单,定义一个windows窗体指针,然后创建窗体和定义窗体标题,接着就是显示了,和gtk主循环了.</p>
		<img alt="p4_2.jpg" src="http://www.cppblog.com/images/cppblog_com/len/WindowsLiveWriter/f5af5ed389e0_9458/p4_2.jpg" border="0" height="346" width="433" />
		<br />
		<h3>让GTK+有点知觉</h3>
		<p>或许你发现了，点击窗体中的"X"关闭按钮，虽然窗体消失了，但是黑色的命令窗口还在，发现＂任务管理器＂中程序还在运行着．对，它并没有像你想的那样，在点击"X"关闭按钮结束掉程序．这些是需要你告诉程序该怎么做的．我们需要在代码中添加相应的事件处理函数. 新增加了destroy函数，它就是事件处理函数，在gtk也可叫做信号处理函数，因为gtk中用信号来进行事件的通知．destory函数的形参是有约定写法的，这个大家可以参见具体的手册．在主程序中，还需要将这一函数与具体的信号进行关联，见第17行．</p>
		<p>在完成这些工作后，你再点击"X"按钮时，会发现"命令行窗口"会出现"按任意键继续"，程序是真正地退出了.</p>
		<pre class="code">/* file gtk.c */
#include 
static void destroy( GtkWidget *widget,
                    gpointer   data )
{
    gtk_main_quit ();            //退出gtk主循环
}

int main(int argc, char* argv[])
{

    GtkWidget* window;
    gtk_init (&amp;argc, &amp;argv);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    
    gtk_window_set_title (GTK_WINDOW (window), "Hello World");
    g_signal_connect (G_OBJECT (window), "destroy",    G_CALLBACK (destroy), NULL);

    gtk_widget_show (window);
    gtk_main();


    return 0;
}
</pre>
		<h3>让黑黑的命令行窗口消失</h3>
		<p>有些人会对这个gtk应用程序总会伴随着黑黑的命令行窗口感到不爽，包括我自己在内．不知道gtk程序在gnome下也是这样，我没有试过，不知道．现在我就使用windows平台的特定方法，来让它消失吧，就是使用WinMain做为主函数．这方法或许不是最正规的做法,但我看来却有效．如果要考虑到跨平台的话，可以用条件编译处理下．</p>
		<pre class="code">/* file gtk.c */
#include <windows.h>
#include 
static void destroy( GtkWidget *widget,
                    gpointer   data )
{
    gtk_main_quit ();            //退出gtk主循环
}

int WinMain(HINSTANCE hInstance,
            HINSTANCE hPrevInstance,
            LPSTR lpCmdLine,
            int nCmdShow
            )
{
    //为应付gtk_init所需要的参数
    int argc=1;    
    char* commandLine={"gtkApplication"};
    char** argv = &amp;commandLine;

    GtkWidget* window;
    gtk_init (&amp;argc, &amp;argv);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    
    gtk_window_set_title (GTK_WINDOW (window), "Hello World");
    g_signal_connect (G_OBJECT (window), "destroy",    G_CALLBACK (destroy), NULL);

    gtk_widget_show (window);
    gtk_main();


    return 0;
}

</windows.h></pre>
		<p>
好啦，现在再编译运行，命令行窗口没有了．你会发现真正的win32窗体了．但是在开发中，我建议用gtk时，还是让命令行窗口显示出来，因为gtk在出错时，会把一些有用的信息打到命令行窗口中，这对你的帮助会很大．</p>
<img src ="http://www.cppblog.com/len/aggbug/45190.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/len/" target="_blank">len</a> 2008-03-23 15:18 <a href="http://www.cppblog.com/len/archive/2008/03/23/45190.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>初识PyGTK</title><link>http://www.cppblog.com/len/archive/2008/03/12/44296.html</link><dc:creator>len</dc:creator><author>len</author><pubDate>Wed, 12 Mar 2008 11:43:00 GMT</pubDate><guid>http://www.cppblog.com/len/archive/2008/03/12/44296.html</guid><wfw:comment>http://www.cppblog.com/len/comments/44296.html</wfw:comment><comments>http://www.cppblog.com/len/archive/2008/03/12/44296.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/len/comments/commentRss/44296.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/len/services/trackbacks/44296.html</trackback:ping><description><![CDATA[
		<style type="text/css"><![CDATA[
pre { 
  padding: 0.5em; 
  margin: 1em 1em; 
  font-weight: bold;
  background: #eeeeee;
  border: solid 1px #aaaaaa;
}
]]&gt;</style>
		<p>PyGTK让你用Python轻松创建具有图形用户界面的程序.底层的GTK+提供了各式的可视元素和功能,如果需要,你能开发在GNOME桌面系统运行的功能完整的软件.</p>
		<p>PyGTK真正具有跨平台性,它能不加修改地,稳定运行各种操作系统之上,如Linux,Windows,MacOS等.除了简单易用和快速的原型开发能力外,PyGTK还有一流的处理本地化语言的独特功能.</p>
		<p>PyGTK是自由软件,所以你能几乎没有任何限制的使用，修改，分发，研究它，它是基于LGPL协议发布的．</p>
		<p>如果你对上面提到的GTK+,也不了解的话，那允许再对它也进行一番介绍．GTK+，用C语言开发的，具有跨平台的GUI库，它是GNOME桌面系统(如果你在用Linux，一定不陌生)和GIMP图象编辑器的开发工具箱．它是世界上许多程序员的选择，对他们来说，国际化的支持是必要的，而且性能也总是他们考虑的因素．与GTK同一领域的还有Qt库，它是由商业公司开发的C++图形库，虽然它也有免费的．</p>
		<p>
				<strong>在windows平台的安装和开发</strong>
		</p>
		<p>安装PyGTK只需执行下列步骤：</p>
		<ul>
				<li>安装Python2.4或以上的windows版本<a href="http://www.python.org]">[www.python.org]</a></li>
				<li>从GTK+/Glade的windows版本的GTK+ 2.10开发运行时环境<a href="http://gladewin32.sourceforge.net/modules/wfdownloads/viewcat.php?cid=14">[gladewin32.sourceforge.net]</a></li>
				<li>从PyGTK网站下载安装PyCairo,PyGobject和PyGTK安装包，注意这些需全部安装才能使PyGTK工作<a href="http://pygtk.org/downloads.html">[pygtk.org]</a></li>
		</ul>
		<p>或许你对这些步骤还感到麻烦，或者对Python不熟悉的话，那也没有关系，直接下载一键安装包<a href="http://osl.ulpgc.es/%7Earc/gnome/pygtk-setup.exe">all-in-one installer</a>,为你配置好全部运行时环境．</p>
		<p>看看开发环境是否配置正确，将下列代码作为Python脚本或者在Python交互控制台下输入．如果正确的话，应该有一个标题为"Hello World"的windows的空窗口呈现在你面前．</p>
		<p>如果不能运行的话，有可能会出现一个不能成功加载dll的错误提示，这是因为缺少iconv.dll．这时需要只需从网上下载过来，拷贝至windows/system32目录下即可了.</p>
		<pre class="code">import gtk
window = gtk.Window()
window.set_title("Hello World")
window.show_all()

gtk.main()
</pre>
<img src ="http://www.cppblog.com/len/aggbug/44296.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/len/" target="_blank">len</a> 2008-03-12 19:43 <a href="http://www.cppblog.com/len/archive/2008/03/12/44296.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PC-lint</title><link>http://www.cppblog.com/len/archive/2008/01/30/42222.html</link><dc:creator>len</dc:creator><author>len</author><pubDate>Wed, 30 Jan 2008 07:18:00 GMT</pubDate><guid>http://www.cppblog.com/len/archive/2008/01/30/42222.html</guid><wfw:comment>http://www.cppblog.com/len/comments/42222.html</wfw:comment><comments>http://www.cppblog.com/len/archive/2008/01/30/42222.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/len/comments/commentRss/42222.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/len/services/trackbacks/42222.html</trackback:ping><description><![CDATA[
		<p>PC-lint for C/C++是由Gimpel软件公司于1985年开发的代码静态分析工具,它能有效地发现程序语法错误、潜在的错误隐患、不合理的编程习惯等。</p>
		<p>FlexeLint for C/C++是在PC_lint在windows平台获得成功后，同样由Gimpel公司开发的，以源代码形式发布的，在Unix/Linux平台上的静态代码分析工具。</p>
		<p>本文主要介绍PC-lint的安装与配置，因此是在windows平台上进行讨论。</p>
		<p>PC-lint支持几乎所有流行的编译器和IDE环境，可能因为其发展历史和面对专业程序员群体的原因，它是以命令行加配置文件的形式进行使用，所以其使用习惯跟现在常见的windows软件不同。</p>
		<p>现以PC-lint与VS2005进行集成来说明：</p>
		<p>将PC-lint释放到某一目录下,如:D:\Program Files\pclint.将新建一std.lnt文件在主目录中，并将添加上以下的内容</p>
		<pre class="code">au-sm.lnt
co-msc80.lnt
lib-mfc.lnt
lib-stl.lnt
lib-w32.lnt
lib-wnt.lnt
lib-atl.lnt
options.lnt  -si4 -sp4

-i "C:\Program Files\Microsoft Visual Studio 8\VC\include"
-i "C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include"
-i "C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\include"
-i "C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\include"
</pre>
		<p>注意：-i后面为相应的vc头文件目录路径,而一系列xxx.lnt是语法配置规则，决定了按什么规则进行检查，以后可以根据需要进行增减. 
写在配置文件中相应的的xxx.lnt从lnt子目录中，拷贝到主目录中．（这一步很重要)
在vs2005中的工具-&gt;外部工具中，点击＂添加",新建一个外部工具.标题可以任意，可取(pc_lint)；命令为：D:\Program Files\pclint\LINT-NT.EXE；参数为:-i"D:\Program Files\pclint" std.lnt "$(ItemFileName)$(ItemExt)";初始目录为：$(ItemDir)，并将下面的＂使用输出窗口＂勾选上.
接下来，就可以写一段程序，在工具菜单中选择pc_lint 来进行检查了．如果你编写的程序有不符合定义的规范，则会在输出窗口中出现相关的信息.</p>
<img src ="http://www.cppblog.com/len/aggbug/42222.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/len/" target="_blank">len</a> 2008-01-30 15:18 <a href="http://www.cppblog.com/len/archive/2008/01/30/42222.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>