久久国产精品77777,久久人人爽人人爽人人片av高请,怡红院日本一道日本久久http://m.shnenglu.com/len/category/15381.htmlzh-cnFri, 05 Nov 2010 15:58:39 GMTFri, 05 Nov 2010 15:58:39 GMT60Python類、模塊、包http://m.shnenglu.com/len/archive/2008/07/24/57078.htmllenlenThu, 24 Jul 2008 11:42:00 GMThttp://m.shnenglu.com/len/archive/2008/07/24/57078.htmlhttp://m.shnenglu.com/len/comments/57078.htmlhttp://m.shnenglu.com/len/archive/2008/07/24/57078.html#Feedback2http://m.shnenglu.com/len/comments/commentRss/57078.htmlhttp://m.shnenglu.com/len/services/trackbacks/57078.htmlPython在處理功能復(fù)用和功能顆粒度劃分時(shí)采用了類、模塊、包的結(jié)構(gòu)。這種處理跟C++中的類和名字空間類似,但更接近于Java所采用的概念。

類的概念在許多語言中出現(xiàn),很容易理解。它將數(shù)據(jù)和操作進(jìn)行封裝,以便將來的復(fù)用。

模塊

模塊,在Python可理解為對應(yīng)于一個(gè)文件。在創(chuàng)建了一個(gè)腳本文件后,定義了某些函數(shù)和變量。你在其他需要這些功能的文件中,導(dǎo)入這模塊,就可重用這些函數(shù)和變量。一般用module_name.fun_name,和module_name.var_name進(jìn)行使用。這樣的語義用法使模塊看起來很像類或者名字空間,可將module_name 理解為名字限定符。模塊名就是文件名去掉.py后綴。下面演示了一個(gè)簡單的例子:

#moduel1.py
def say(word):
    print word

#caller.py
import module1

print __name__
print module1.__name__
module1.say('hello')
$ python caller.py
__main__
module1
hello

例子中演示了從文件中調(diào)用模塊的方法。這里還展示了一個(gè)有趣的模塊屬性__name__,它的值由Python解釋器設(shè)定。如果腳本文件是作為主程序調(diào)用,其值就設(shè)為__main__,如果是作為模塊被其他文件導(dǎo)入,它的值就是其文件名。這個(gè)屬性非常有用,常可用來進(jìn)行模塊內(nèi)置測試使用,你會經(jīng)常在一些地方看到類似于下面的寫法,這些語句只在作為主程序調(diào)用時(shí)才被執(zhí)行。

if __name__ == '__main__':
    app = wxapp(0)
    app.MainLoop()

模塊搜索路徑

上面的例子中,當(dāng)module1被導(dǎo)入后,python解釋器就在當(dāng)前目錄下尋找module1.py的文件,然后再從環(huán)境變量PYTHONPATH尋找,如果這環(huán)境變量沒有設(shè)定,也不要緊,解釋器還會在安裝預(yù)先設(shè)定的的一些目錄尋找。這就是在導(dǎo)入下面這些標(biāo)準(zhǔn)模塊,一切美好事情能發(fā)生的原因。

import os
import sys
import threading
...

這些搜索目錄可在運(yùn)行時(shí)動(dòng)態(tài)改變,比如將module1.py不放在當(dāng)前目錄,而放在一個(gè)冷僻的角落里。這里你就需要通過某種途徑,如sys.path,來告知Python了。sys.path返回的是模塊搜索列表,通過前后的輸出對比和代碼,應(yīng)能理悟到如何增加新路徑的方法了吧。非常簡單,就是使用list的append()或insert()增加新的目錄。

#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
$ python module2.py
['e:\\Project\\Python', 'C:\\WINDOWS\\system32\\python25.zip', ...]
['e:\\Project\\Python\\modules', 'e:\\Project\\Python', 'C:\\WINDOWS\\system32\\python25.zip', ...]

其他的要點(diǎn)

模塊能像包含函數(shù)定義一樣,可包含一些可執(zhí)行語句。這些可執(zhí)行語句通常用來進(jìn)行模塊的初始化工作。這些語句只在模塊第一次被導(dǎo)入時(shí)被執(zhí)行。這非常重要,有些人以為這些語句會多次導(dǎo)入多次執(zhí)行,其實(shí)不然。

模塊在被導(dǎo)入執(zhí)行時(shí),python解釋器為加快程序的啟動(dòng)速度,會在與模塊文件同一目錄下生成.pyc文件。我們知道python是解釋性的腳本語言,而.pyc是經(jīng)過編譯后的字節(jié)碼,這一工作會自動(dòng)完成,而無需程序員手動(dòng)執(zhí)行。

在創(chuàng)建許許多多模塊后,我們可能希望將某些功能相近的文件組織在同一文件夾下,這里就需要運(yùn)用包的概念了。包對應(yīng)于文件夾,使用包的方式跟模塊也類似,唯一需要注意的是,當(dāng)文件夾當(dāng)作包使用時(shí),文件夾需要包含__init__.py文件,主要是為了避免將文件夾名當(dāng)作普通的字符串。__init__.py的內(nèi)容可以為空,一般用來進(jìn)行包的某些初始化工作或者設(shè)置__all__值,__all__是在from package-name import *這語句使用的,全部導(dǎo)出定義過的模塊。



len 2008-07-24 19:42 發(fā)表評論
]]>
wxPython和XRC文件實(shí)現(xiàn)i18nhttp://m.shnenglu.com/len/archive/2008/07/15/56229.htmllenlenTue, 15 Jul 2008 12:21:00 GMThttp://m.shnenglu.com/len/archive/2008/07/15/56229.htmlhttp://m.shnenglu.com/len/comments/56229.htmlhttp://m.shnenglu.com/len/archive/2008/07/15/56229.html#Feedback0http://m.shnenglu.com/len/comments/commentRss/56229.htmlhttp://m.shnenglu.com/len/services/trackbacks/56229.html應(yīng)用程序國際化,在開源世界里常以i18n被提及,i18n是Internationalization的簡寫,正好18個(gè)字母。在wxPython程序進(jìn)行i18n,如果字符串是編碼在源文件中時(shí),完全可按照python程序的i18n的方法,即使用gexttext和locale模塊。而wxPython程序在使用XRC文件做為界面資源時(shí),則應(yīng)使用wx.Locale模塊,它封裝了區(qū)域化相關(guān)的操作。i18n,或者國際化實(shí)際上涉及到語言習(xí)慣,數(shù)字格式等等類別的內(nèi)容。這里只介紹語言多國化,將一個(gè)簡單的英文程序轉(zhuǎn)換為中文,涉及到源文件,可從這里下載。

創(chuàng)建PO文件

PO文件是Portable Object文件的簡稱,它包含需要翻譯的字符串。我們需要從源文件進(jìn)行提取。首先,對源文件test.py編輯,標(biāo)識代碼里需要翻譯的字符串內(nèi)容。我們使用_("xx")的方法,這種形式可能在許多開源源代碼中見識過。

#加載菜單欄
menubar = rc.LoadMenuBar('IDR_MENU')

這里的IDR_MENU是資源標(biāo)識ID,不需要翻譯,因此不做改變,而下面的代碼:

info.SetVersion('1.0')
info.SetDescription('XRC i18n Demo')

'XRC i18n Demo'是描述性的文本,需要進(jìn)行翻譯,將需要處理為

info.SetVersion('1.0')
info.SetDescription(_('XRC i18n Demo'))

接著需要生成.pot(Portable Object Template),這是po的模板文件。在將來程序可能配置成其他語種,其他語言的po文件都從它而來。為了創(chuàng)建這文件,需要用到GNU gettext工具集中的xgettext。向xgettext傳入些必要的信息,來創(chuàng)建.pot文件。

>xgetttext --output=test.pot test.py

我們將wxPython界面以XRC文件保存了,那里同樣有要翻譯的字符串需要提取。用XRCed工具將XRC生成python代碼,勾選上'Generate gettext strings'項(xiàng)即可。將源文件和XRC生成的test_xrc.py文件一起處理,生成一個(gè)test.pot。

>xgettext --output=test.pot test.py test_xrc.py

將得到的test.pot另存為test.po文件,然后進(jìn)行翻譯編輯,在這過程中文件需要使用utf-8編碼。將對應(yīng)的英文翻譯成中文,將charset更改為utf-8。

"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: test.py:19
msgid "XRC i18n Demo"
msgstr "XRC 國際化示例"
...

.pot和.po這些文件都是文本文件,主要供翻譯者使用。為了使程序在運(yùn)行時(shí)能獲取相關(guān)的翻譯的內(nèi)容,要進(jìn)行所謂的編譯過程,將文本文件轉(zhuǎn)換為二進(jìn)制文件.mo。這里用了gettext工具集中的另一程序msgfmt。

> msgfmt --output=test.mo test.po

因?yàn)閣indows下沒有像linux像有公共存儲.mo文件的目錄,保持平臺的遷移性,在應(yīng)用程序本地目錄下新建locale目錄,用來存放編譯過的.mo文件,然后將test.mo移動(dòng)至locale目錄。在完成這些步驟后,就轉(zhuǎn)入代碼方面的更改了。

wxPython代碼更改

原先的代碼只需要做小改動(dòng):

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

首先,增加了新的目錄文件路徑,這將使wxPython搜索這個(gè)目錄,尋找匹配的.mo文件。接著創(chuàng)建wx.Locale對象,將其初始化為簡體中文,這將對應(yīng)于zh_CN。最后將wx.GetTranslation做了一全局映射,這樣你在其他類中,比如示例中TestFrame也能使用_('xx')調(diào)用。這樣wxPython的i18n工作就完成了,下面是翻譯前后的界面截圖。

wxpython

一些有益的討論

.mo文件的查找目錄

如果你將locale目錄下的test.mo文件刪除掉,然后將test.py中的wx.LANGUAGE_CHINESE_SIMPLIFIED改為wx.LANGUAGE_CHINESE,重新運(yùn)行程序看看。發(fā)現(xiàn)界面變成了如下的繁體中文,但是菜單'檔案'下的Exit還是英文。

wxzh

因?yàn)槿笔?mo文件,但又指定wx.LANGUAGE_CHINESE,wxPython運(yùn)行時(shí)使用了wxstd.mo文件。wxstd.mo有許多預(yù)編譯好的常見字符串的對應(yīng)關(guān)系,它隨wxPython發(fā)布,在wx/locale下有許多語言版本的wxstd.mo。

對于wxPython會對待查目錄"DIR"來搜索.mo文件,查找它下面的這些目錄,(DIR/LANG/LC_MESSAGES;DIR/LANG;DIR),對于哪些是待查目錄,各個(gè)系統(tǒng)下又有不同,在所有的平臺上,LC_PATH環(huán)境變量指定的目錄將成為待查目錄,在Linux下/share/locale, /usr/share/locale, /usr/lib/locale, /usr/locale /share/locale以及當(dāng)前目錄將是待查目錄。在上面我們已經(jīng)用過AddCatalogLookupPathPrefix()函數(shù),其作用就是增加自己的待查目錄。

在示例程序中,將test.mo放在locale\zh_CN\LC_MESSAGES或者locale\zh\LC_MESSAGES同樣是可行的。但是如果使用wx.LANGUAGE_CHINESE指定,則zh_CN目錄將不可行,因?yàn)樗皇翘鼗夸洠负嗴w中文,而zh目錄同樣適用。

工具鏈再討論

gettext進(jìn)行國際化是開源社區(qū)的主流方案,它也提供了許多實(shí)用工具供使用。上面提到了xgettext,msgfmt,還有msginit.exe,它將根據(jù).pot文件創(chuàng)建新的.po文件,然后初始化一些元信息,像作者信息,項(xiàng)目,以及編碼等,當(dāng)然也可像上面的手工編輯。msgmerge.exe將兩個(gè).po文件進(jìn)行合并。除了使用GNU Gettext工具集,也可使用隨python發(fā)布的tool\i18n目錄下pygettext.py和msgfmt.py,它們等同于上述的兩個(gè)工具。

對于編輯.po文件,可以嘗試一下Poedit,它提供了圖形化的編輯環(huán)境,其他功能我就不清楚了。



len 2008-07-15 20:21 發(fā)表評論
]]>
開發(fā)Windows Live Writer插件小記http://m.shnenglu.com/len/archive/2008/07/05/55423.htmllenlenSat, 05 Jul 2008 13:43:00 GMThttp://m.shnenglu.com/len/archive/2008/07/05/55423.htmlhttp://m.shnenglu.com/len/comments/55423.htmlhttp://m.shnenglu.com/len/archive/2008/07/05/55423.html#Feedback0http://m.shnenglu.com/len/comments/commentRss/55423.htmlhttp://m.shnenglu.com/len/services/trackbacks/55423.htmlWindows Live Writer是寫博客的利器,非常好用。只是對一些常見的html標(biāo)簽支持不足,比如沒有預(yù)排文本標(biāo)簽<pre>之類的。在插入示例代碼時(shí),我不喜歡使用網(wǎng)上的那些高亮插件,它們增加了一些我感覺不友好的標(biāo)簽元素。我在寫文章時(shí),代碼放在<pre>標(biāo)簽,然后使用自定義的code類,如果是一些屏幕輸入輸入文本,會用一個(gè)console類來進(jìn)行說明。如果直接從源代碼拷貝文本至html源文件時(shí),xml文件的的<>"之類標(biāo)簽需要進(jìn)行轉(zhuǎn)義才可以。在這之前,我都需要手工將WLW切換到HTML模式進(jìn)行創(chuàng)作,然后修改這些標(biāo)簽,非常麻煩。這樣干了幾次后,昨天決定自己寫個(gè)WLW插件用。在搜索引擎的幫助下,找到Dflying Chen的 為Windows Live Writer開發(fā)插件——InsertSearchPageLink這篇文章,并在其參照完成了插件編寫。

但在找到這篇文章之前,和編寫插件的過程中,還是費(fèi)了很多功夫。最早我認(rèn)為寫插件是需要下載SDK之類的軟件,所以在Live Writer官方開發(fā)網(wǎng)站,Live Writer網(wǎng),MSDN之類的找了個(gè)遍,看見是有SDK之類字樣的下載,但弄不下來只有文檔,根本不見其什么頭文件,DLL之類的。在這花費(fèi)了很多時(shí)間,最后才發(fā)現(xiàn)WLW插件的SDK是隨WLW一起分發(fā)了,也就是WindowsLive.Writer.Api.dll之類的,這些dll 都隨WLW主程序在一個(gè)目錄中。還有一點(diǎn)是,現(xiàn)在WLW在中國是隨Live套件一起發(fā)布的,因此路徑由原來的C:\Program Files\Windows Live Writer變成了C:\Program Files\Windows Live\Writer,插件目錄為Plugin。如果在網(wǎng)上發(fā)現(xiàn)有好用的插件,只需要將其發(fā)布的插件dll扔到這個(gè)目錄就行了。

在開發(fā)中碰到圖標(biāo)資源不能成功加載,在Dflying Chen的文章中特意提到了圖標(biāo)資源需要是嵌入形式,我也按照其操作的,總以為是這里出現(xiàn)問題。后來花了一些時(shí)間,才找到總是的根源:自己在開發(fā)中更改了工程名,導(dǎo)致最后生成的程序集的名稱與后來的命名空間名稱不一致,圖標(biāo)路徑就出錯(cuò)了。C#也只是這次用一下,這些都沒有接觸到。

昨天弄完自己的“插入Pre標(biāo)記”插件后,想到自己寫博客常需要截圖,遂想再開發(fā)一個(gè)截圖工具的。最早搜到了別人調(diào)用SnagIt搜件,不好用,因?yàn)镾nagIt是商業(yè)軟件,需要注冊的。后來找到了picpick,小巧免費(fèi),非常實(shí)用。我想調(diào)用picpick的,但是在參照Insert SnagIt Screen Capture發(fā)現(xiàn)是用COM接口,而無奈picpick沒有這樣供開發(fā)使用的接口考慮,最終不可行。后來經(jīng)過一些其他的嘗試,都告失敗。最后還是搜索幫了忙,找到了Screen Capture這個(gè)插件,原來有別人已完工了。

最后附上,我用這個(gè)新插件截的圖,非常好用,只需一步:

tmp196



len 2008-07-05 21:43 發(fā)表評論
]]>
(翻譯)Python標(biāo)準(zhǔn)庫的threading.Thread類http://m.shnenglu.com/len/archive/2008/06/24/54472.htmllenlenTue, 24 Jun 2008 08:54:00 GMThttp://m.shnenglu.com/len/archive/2008/06/24/54472.htmlhttp://m.shnenglu.com/len/comments/54472.htmlhttp://m.shnenglu.com/len/archive/2008/06/24/54472.html#Feedback0http://m.shnenglu.com/len/comments/commentRss/54472.htmlhttp://m.shnenglu.com/len/services/trackbacks/54472.html這個(gè)類表示在單獨(dú)的控制線程中運(yùn)行的活動(dòng)。有兩種方法可以指定這種活動(dòng),給構(gòu)造函數(shù)傳遞回調(diào)對象,或者在子類中重寫run() 方法。其他方法(除了構(gòu)造函數(shù))都不應(yīng)在子類中被重寫。換句話說,在子類中只有__init__()run()方法被重寫。

一旦線程對象被創(chuàng)建,它的活動(dòng)需要通過調(diào)用線程的start()方法來啟動(dòng)。這方法再調(diào)用控制線程中的run方法。

一旦線程被激活,則這線程被認(rèn)為是'alive'(活動(dòng))。當(dāng)它的run()方法終止時(shí)-正常退出或拋出未處理的異常,則活動(dòng)狀態(tài)停止。isAlive()方法測試線程是否是活動(dòng)的。

一個(gè)線程能調(diào)用別的線程的join()方法。這將阻塞調(diào)用線程,直到擁有join()方法的線程的調(diào)用終止。

線程有名字。名字能傳給構(gòu)造函數(shù),通過setName()方法設(shè)置,用getName()方法獲取。

線程能被標(biāo)識為'daemon thread'(守護(hù)線程).這標(biāo)志的特點(diǎn)是當(dāng)剩下的全是守護(hù)線程時(shí),則Python程序退出。它的初始值繼承于創(chuàng)建線程。這標(biāo)志用setDaemon()方法設(shè)置,用isDaemon()獲取。

存在'main thread'(主線程),它對應(yīng)于Python程序的初始控制線程。它不是后臺線程。

有可能存在'dummy thread objects'(啞線程對象)被創(chuàng)建。這些線程對應(yīng)于'alien threads'(外部線程),它們在Python的線程模型之外被啟動(dòng),像直接從C語言代碼中啟動(dòng)。啞線程對象只有有限的功能,它們總是被認(rèn)為是活動(dòng)的,守護(hù)線程,不能使用join()方法。它們從不能被刪除,既然它無法監(jiān)測到外部線程的中止。

class Thread(group=None, target=None, name=None, args=(), kwargs={})

構(gòu)造函數(shù)能帶有關(guān)鍵字參數(shù)被調(diào)用。這些參數(shù)是:

group 應(yīng)當(dāng)為 None,為將來實(shí)現(xiàn)ThreadGroup類的擴(kuò)展而保留。

target 是被 run()方法調(diào)用的回調(diào)對象. 默認(rèn)應(yīng)為None, 意味著沒有對象被調(diào)用。

name 為線程名字。默認(rèn),形式為'Thread-N'的唯一的名字被創(chuàng)建,其中N 是比較小的十進(jìn)制數(shù)。

args是目標(biāo)調(diào)用參數(shù)的tuple,默認(rèn)為()。

kwargs是目標(biāo)調(diào)用的參數(shù)的關(guān)鍵字dictionary,默認(rèn)為{}。

如果子線程重寫了構(gòu)造函數(shù),它應(yīng)保證調(diào)用基類的構(gòu)造函數(shù)(Thread.__init__()),在線程中進(jìn)行其他工作之前。

start()
啟動(dòng)線程活動(dòng)。

在每個(gè)線程對象中最多被調(diào)用一次。它安排對象的run() 被調(diào)用在一單獨(dú)的控制線程中。

run()

用以表示線程活動(dòng)的方法。

你可能在子類重寫這方法。標(biāo)準(zhǔn)的 run()方法調(diào)用作為target傳遞給對象構(gòu)造函數(shù)的回調(diào)對象。如果存在參數(shù),一系列關(guān)鍵字參數(shù)從argskwargs參數(shù)相應(yīng)地起作用。

join([timeout])
等待至線程中止。這阻塞調(diào)用線程直至線程的join() 方法被調(diào)用中止-正常退出或者拋出未處理的異常-或者是可選的超時(shí)發(fā)生。

當(dāng)timeout參數(shù)未被設(shè)置或者不是None,它應(yīng)當(dāng)是浮點(diǎn)數(shù)指明以秒計(jì)的操作超時(shí)值。因?yàn)?tt>join()總是返回None,你必須調(diào)用isAlive()來判別超時(shí)是否發(fā)生。

當(dāng)timeout 參數(shù)沒有被指定或者是None時(shí),操作將被阻塞直至線程中止。

線程能被join()許多次。

線程不能調(diào)用自身的join(),因?yàn)檫@將會引起死鎖。

在線程啟動(dòng)之前嘗試調(diào)用join()會發(fā)生錯(cuò)誤。

getName()
返回線程名。
setName(name)
設(shè)置線程名。

這名字是只用來進(jìn)行標(biāo)識目的的字符串。它沒有其他作用。多個(gè)線程可以取同一名字。最初的名字通過構(gòu)造函數(shù)設(shè)置。

isAlive()
返回線程是否活動(dòng)的。

大致上,線程從 start()調(diào)用開始那點(diǎn)至它的run()方法中止返回時(shí),都被認(rèn)為是活動(dòng)的。模塊函數(shù)enumerate()返回活動(dòng)線程的列表。

isDaemon()
返回線程的守護(hù)線程標(biāo)志。
setDaemon(daemonic)
設(shè)置守護(hù)線程標(biāo)志為布爾值daemonic。它必須在start()調(diào)用之前被調(diào)用。

初始值繼承至創(chuàng)建線程。

當(dāng)沒有活動(dòng)的非守護(hù)線程時(shí),整個(gè)Python程序退出。

參見:Python Library Reference



len 2008-06-24 16:54 發(fā)表評論
]]>
Boost.Program_options簡述http://m.shnenglu.com/len/archive/2008/06/15/53368.htmllenlenSun, 15 Jun 2008 13:03:00 GMThttp://m.shnenglu.com/len/archive/2008/06/15/53368.htmlhttp://m.shnenglu.com/len/comments/53368.htmlhttp://m.shnenglu.com/len/archive/2008/06/15/53368.html#Feedback0http://m.shnenglu.com/len/comments/commentRss/53368.htmlhttp://m.shnenglu.com/len/services/trackbacks/53368.html介紹

命令行接口是普遍,基礎(chǔ)的人機(jī)交互接口,從命令行提取程序的運(yùn)行時(shí)選項(xiàng)的方法有很多。你可以自己編寫相對應(yīng)的完整的解析函數(shù),或許你有豐富的C語言編程經(jīng)驗(yàn),熟知getopt()函數(shù)的用法,又或許使用Python的你已經(jīng)在使用optparse庫來簡化這一工作。大家在平時(shí)不斷地談及到“不要重復(fù)造輪子”,那就需要掌握一些順手的庫,這里介紹一種C++方式來解析命令行選項(xiàng)的方法,就是使用Boost.Program_options庫。

program_options提供程序員一種方便的命令行和配置文件進(jìn)行程序選項(xiàng)設(shè)置的方法。使用program_options庫而不是你自己動(dòng)手寫相關(guān)的解析代碼,因?yàn)樗唵危暶鞒绦蜻x項(xiàng)的語法簡潔,并且?guī)熳陨硪卜浅P ⑦x項(xiàng)值轉(zhuǎn)換為適合的類型值的工作也都能自動(dòng)完成。庫有著完備的錯(cuò)誤檢查機(jī)制,如果自己手寫解析代碼時(shí),就可能會錯(cuò)過對一些出錯(cuò)情況的檢查了。最后,選項(xiàng)值不僅能從命令行獲取,也能從配置文件,甚至于環(huán)境變量中提取,而這些選擇不會增加明顯的工作量。

示例說明

以下面簡單的hello程序進(jìn)行說明,默認(rèn)打印hello world,如果傳入-p選項(xiàng),就會打印出人的姓名,另外通過傳入-h選項(xiàng),可以打印出幫助選項(xiàng)。略微看一眼代碼文件和相應(yīng)的屏幕輸入輸出,然后我們再一起來看看這些是如何發(fā)生的。

//hello.cpp 
#include <iostream>
#include <string>
#include <boost/program_options.hpp>

using namespace std;
int main(int argc, char* argv[])
{
    using namespace boost::program_options;
    //聲明需要的選項(xiàng)
    options_description desc("Allowed options");
    desc.add_options()
        ("help,h", "produce help message")
        ("person,p", value<string>()->default_value("world"), "who")
        ;

    variables_map vm;        
    store(parse_command_line(argc, argv, desc), vm);
    notify(vm);    

    if (vm.count("help")) {
        cout << desc;
        return 0;
    }
    cout << "Hello " << vm["person"].as<string>() << endl;
    return 0;
}

下面是在Windows命令提示符窗口上的輸入輸出結(jié)果,其中">"表示提示符。

>hello 
Hello world

>hello -h
Allowed options:
  -h [ --help ]                produce help message
  -p [ --person ] arg (=world) who

>hello --person len
Hello len

首先通過options_description類聲明了需要的選項(xiàng),add_options返回了定義了operator()的特殊的代理對象。這個(gè)調(diào)用看起來有點(diǎn)奇怪,其參數(shù)依次為選項(xiàng)名,選項(xiàng)值,以及選項(xiàng)的描述。注意到示例中的選項(xiàng)名為"help,h",是因?yàn)槁暶髁司哂卸踢x項(xiàng)名和長選項(xiàng)名的選項(xiàng),這跟gnu程序的命令行具有一致性。當(dāng)然你可以省略短選項(xiàng)名,但是這樣就不能用命令選項(xiàng)簡寫了。第二個(gè)選項(xiàng)的聲明,定義了選項(xiàng)值為string類型,其默認(rèn)值為world.

接下來,聲明了variables_map類的對象,它主要用來存儲選項(xiàng)值,并且能儲存任意類型的值。然后,store,parse_command_line和notify函數(shù)使vm能存儲在命令行中發(fā)現(xiàn)的選項(xiàng)。

最后我們就自由地使用這些選項(xiàng)了,variables_map類的使用就像使用std::map一樣,除了它必須用as方法去獲取值。如果as方法調(diào)用的指定類型與實(shí)際存儲的類型不同,就會有異常拋出。

具有編程的你可能有這樣的經(jīng)驗(yàn),使用cl或gcc對源文件進(jìn)行編譯時(shí),可直接將源文件名放置在命令行中,而無需什么選項(xiàng)字母,如gcc a.c之類的。prgram_options也能處理這種情況,在庫中被稱為"positional options"(位置選項(xiàng)),但這需要程序員的一點(diǎn)兒幫助才能完成。看下面的經(jīng)過對應(yīng)修改的代碼,我們無需傳入"-p"選項(xiàng),就能可指定"person"選項(xiàng)值

    positional_options_description p;
    p.add("person", -1);
    store(command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
>hello len
Hello len

前面新增的兩行是為了說明所有的位置選項(xiàng)都應(yīng)被解釋成"person"選項(xiàng),這里還采用了command_line_parser類來解析命令行,而不是用parse_command_line函數(shù)。后者只是對前者類的簡單封裝,但是現(xiàn)在我們需要傳入一些額外的信息,所以要使用類本身。

選項(xiàng)復(fù)合來源

一般來說,在命令行上指定所有選項(xiàng),對用戶來說是非常煩人的。如果有些選項(xiàng)要應(yīng)用于每次運(yùn)行,那該怎么辦呢。我們當(dāng)然希望能創(chuàng)建出帶有些常用設(shè)置的選項(xiàng)文件,跟命令行一起應(yīng)用于程序中。當(dāng)然這一切需要將命令行與配置文件中的值結(jié)合起來。比如,在命令行中指定的某些選項(xiàng)值應(yīng)該能覆蓋配置文件中的對應(yīng)值,或者將這些值組合起來。

下面的代碼段將選項(xiàng)通過文件讀取,這文件是文本格式,可用"#"表示注釋,格式如命令行中的參數(shù)一樣,選項(xiàng)=值

    ifstream ifs("config.cfg");
    store(parse_config_file(ifs,config),vm);
    notify(vm);

參考

Boost.prgram_options庫文檔



len 2008-06-15 21:03 發(fā)表評論
]]>
Boost.Lambda簡述http://m.shnenglu.com/len/archive/2008/05/18/50286.htmllenlenSun, 18 May 2008 08:03:00 GMThttp://m.shnenglu.com/len/archive/2008/05/18/50286.htmlhttp://m.shnenglu.com/len/comments/50286.htmlhttp://m.shnenglu.com/len/archive/2008/05/18/50286.html#Feedback3http://m.shnenglu.com/len/comments/commentRss/50286.htmlhttp://m.shnenglu.com/len/services/trackbacks/50286.htmlBoost.Lambda是什么?

Boost Lambda庫是C++模板庫,以C++語言實(shí)現(xiàn)了lambda抽象.Lambda這個(gè)術(shù)語來自函數(shù)編程語言和lambda閉包理論,lambda抽象實(shí)際上定義了匿名函數(shù).了解過C#新引入的匿數(shù)函數(shù)特性或Lisp編程的人,對這些概念理解會有很大幫助.Lambda庫設(shè)計(jì)的主要?jiǎng)訖C(jī)是為STL算法提供靈活方便的定義匿名函數(shù)對象的機(jī)制.這個(gè)Lambda庫究竟是有什么用呢?代碼勝千言!看下面將STL容器中的元素打印到標(biāo)準(zhǔn)輸出上的代碼.

for_each(a.begin(), a.end(), std::cout << _1 << ' ');

表達(dá)式std::cout << _1 << ' '定義了一元函數(shù)對象.變量_1是函數(shù)的形參,是實(shí)參的占位符.每次for_each的迭代中,函數(shù)帶著實(shí)際的參數(shù)被調(diào)用,實(shí)際參數(shù)取代了占位符,然后函數(shù)體里的內(nèi)容被執(zhí)行.Lambda庫的核心就是讓你能像上面所展示的那樣,在STL算法的調(diào)用點(diǎn),定義小的匿名函數(shù)對象.

Lambda庫的安裝

Lambda庫只由頭文件組成,這就意味著你不需要進(jìn)行任何編譯,連接,生成二進(jìn)制庫的動(dòng)作,只需要boost庫頭文件路徑包含進(jìn)你的工程中即可使用.

與現(xiàn)代的C++語言一樣,在使用時(shí)你需要聲明用到的名字空間,把下列的代碼包含在你的源文件頭:

using namespace boost::lambda;

Boost Lambda庫的動(dòng)機(jī)

在標(biāo)準(zhǔn)模板庫STL成為標(biāo)準(zhǔn)C++的一部分后,典型的STL算法對容器中元素的操作大都是通過函數(shù)對象(function objects)完成的.這些函數(shù)作為實(shí)參傳入STL算法.

任何C++中以函數(shù)調(diào)用語法被調(diào)用的對象都是函數(shù)對象.STL對某些常見情況預(yù)置了些函數(shù)對象.比如:plus,less,not1下面就是標(biāo)準(zhǔn)plus模板的一種可能實(shí)現(xiàn):
template <class T> 
struct plus : public binary_function <T, T, T> {
  T operator()(const T& i, const T& j) const {
    return i + j; 
  }
};

基類binary_function<T, T, T>包含了參數(shù)和函數(shù)對象返回類型的類型定義,這樣可使得函數(shù)對象可配接.

除了上面提到的基本的函數(shù)對象外,STL還包含了binder模板,將可配接的二元函數(shù)中的某個(gè)實(shí)參固定為常量值,來創(chuàng)建一個(gè)一元函數(shù)對象.比如:

class plus_1 {
  int _i;
public:
  plus_1(const int& i) : _i(i) {}
  int operator()(const int& j) { return _i + j; }
};

上面的代碼顯性地創(chuàng)建了一個(gè)函數(shù)對象,將其參數(shù)加1.這樣的功能可用plus模板與binder模板(bind1st來等效地實(shí)現(xiàn).舉例來說,下面的兩行表達(dá)式創(chuàng)建了一個(gè)函數(shù)對象,當(dāng)它被調(diào)用時(shí),將返回1與調(diào)用參數(shù)的和.

plus_1(1)
bind1st(plus<int>(), 1)

plus<int>就是計(jì)算兩個(gè)數(shù)之和的函數(shù)對象.bind1st使被調(diào)用的函數(shù)對象的第一個(gè)參數(shù)綁定到常量1.作為上面函數(shù)對象的使用示例,下面的代碼就是將容器a中的元素加1后,輸出到標(biāo)準(zhǔn)輸出設(shè)備:

transform(a.begin(), a.end(), ostream_iterator<int>(cout),
          bind1st(plus<int>(), 1));

為了使binder更加通用,STL包含了適配器(adaptors)用于函數(shù)引用與指針,以及成員函數(shù)的配接.

所有這些工具都有一個(gè)目標(biāo),就是為了能在STL算法的調(diào)用點(diǎn)有可能指定一個(gè)匿名的函數(shù),換句說,就是能夠使部分代碼片斷作為參數(shù)傳給調(diào)用算法函數(shù).但是,標(biāo)準(zhǔn)庫在這方面只做了部分工作.上面的例子說明用標(biāo)準(zhǔn)庫工具進(jìn)行匿名函數(shù)的定義還是很麻煩的.復(fù)雜的函數(shù)調(diào)用表達(dá)式,適配器,函數(shù)組合符都使理解變得困難.另外,在運(yùn)用標(biāo)準(zhǔn)庫這些方法時(shí)還有明顯的限束.比如,標(biāo)準(zhǔn)C++98中的binder只允許二元函數(shù)的一個(gè)參數(shù)被綁定,而沒有對3參數(shù),4參數(shù)的綁定.這種情況在TR1實(shí)施后,引進(jìn)了通用的binder后可能改善,對于使用MSVC的程序員,有興趣還可以查看下微軟針對VS2008發(fā)布的TR1增強(qiáng)包.

但是不管怎樣,Lambda庫提供了針對這些問題比較優(yōu)雅的解決方法:

  • 對匿名函數(shù)以直觀的語義進(jìn)行創(chuàng)建,上面的例子可改寫成:

    transform(a.begin(), a.end(), ostream_iterator<int>(cout), 
              1 + _1);
    

    更直觀點(diǎn):

    for_each(a.begin(), a.end(), cout << (1 + _1));
    
  • 絕大部分對函數(shù)參數(shù)綁定的限制被去除,在實(shí)際C++代碼中可以綁定任意的參數(shù)

  • 分離的函數(shù)組合操作不再需要了,函數(shù)組合被隱性地支持.

Lambda表達(dá)式介紹

Lambda表達(dá)在函數(shù)式編程語言中很常見.在不同語言中,它們的語法有著很大不同,但是lambda表達(dá)式的基本形式是:

lambda x1...xn.e

lambda表達(dá)式定義了匿名函數(shù),并由下列的元素組成

  • 函數(shù)的參數(shù):x1...xn
  • 表達(dá)式e,以參數(shù)x1...xn的形式計(jì)算函數(shù)的值

一個(gè)簡單的lambda表達(dá)式的例子是:

(lambda x y.x+y) 2 3 = 2 + 3 = 5 

在lambda表達(dá)式的C++版本中,表達(dá)式中x1...xn不需要,已預(yù)定義形式化的參數(shù).在現(xiàn)在Boost.Lambda庫中,存在三個(gè)這樣的預(yù)定義的參數(shù),叫做占位符:_1,_2,和_3.它們分別指代在lambda表達(dá)式中的第一,二,三個(gè)參數(shù).比如,下面這樣的lambda表達(dá)式:

lambda x y.x+y

C++定義的形式將會是這樣:

_1 + _2

因此在C++中的lambda表達(dá)式?jīng)]有語義上所謂的關(guān)鍵字.占位符作為運(yùn)算符使用時(shí)就隱性地意味著運(yùn)算符調(diào)用是個(gè)lambda表達(dá)式.但是只有在作為運(yùn)算符調(diào)用才是這樣.當(dāng)Lambda表達(dá)式包含函數(shù)調(diào)用,控制結(jié)構(gòu),轉(zhuǎn)換時(shí)就需要特殊的語法調(diào)用了.更為重要的是,作為函數(shù)調(diào)用是需封裝成binder函數(shù)的形式.比如,下面這個(gè)lambda表達(dá)式:

lambda x y.foo(x,y)

不應(yīng)寫成foo(_1,_2),對應(yīng)的C++結(jié)構(gòu)應(yīng)如下:

bind(foo, _1, _2)

對于這種表達(dá)式,更傾向于作為綁定表達(dá)式bind expressions

lambda表達(dá)式定義了C++的函數(shù)對象,因此,對于函數(shù)調(diào)用的形式跟其他的函數(shù)對象一樣,比如:(_1 + _2)(i, j).

性能

性能,運(yùn)行效率,總是C++程序員關(guān)心的話題.理論上,相對于手寫循環(huán)代碼,使用STL算法和Lambda函數(shù)對象的所有運(yùn)行開銷,可以通過編譯優(yōu)化消除掉.這種優(yōu)化取決于編譯器,實(shí)際中的編譯器大都能做到.測試表明,性能會有下降,但是影響不大,對于代碼的效率和簡潔之間的權(quán)衡,只能由程序員自己做出判斷了.

Lambda庫的設(shè)計(jì)與實(shí)現(xiàn)中大量運(yùn)用了模板技術(shù),造成對于同一模板需要大量的遞歸實(shí)例化.這一因素可能使構(gòu)建復(fù)雜邏輯的lambda表達(dá)式,不是一個(gè)非常理想的做法.因?yàn)榫幾g這些表達(dá)式需要大量的內(nèi)存,從而使編譯時(shí)間變得非常慢,這在一些大型項(xiàng)目中會更加突出.還有在發(fā)生編誤錯(cuò)誤時(shí),引發(fā)的大量錯(cuò)誤信息,不能有效地指出真正錯(cuò)誤之處.最后點(diǎn),C++標(biāo)準(zhǔn)建議模板的嵌套層次不要超過17層來防止導(dǎo)致無限遞歸,而復(fù)雜的Lambda表達(dá)式模板會很容易超過這一限制.雖然大多數(shù)編譯器允許更深層次的模板嵌套,但是通常需要顯性地傳入一個(gè)命令行參數(shù)才能做到.

參考

大多數(shù)內(nèi)容是從Boost.Lambday庫在線文檔參考翻譯而成



len 2008-05-18 16:03 發(fā)表評論
]]>
(翻譯)設(shè)計(jì)Qt風(fēng)格的C++的應(yīng)用程序接口http://m.shnenglu.com/len/archive/2008/05/11/49563.htmllenlenSun, 11 May 2008 12:07:00 GMThttp://m.shnenglu.com/len/archive/2008/05/11/49563.htmlhttp://m.shnenglu.com/len/comments/49563.htmlhttp://m.shnenglu.com/len/archive/2008/05/11/49563.html#Feedback6http://m.shnenglu.com/len/comments/commentRss/49563.htmlhttp://m.shnenglu.com/len/services/trackbacks/49563.html "Designing Qt-Style C++ APIs" by Matthias Ettrich

http://doc.trolltech.com/qq/qq13-apis.html

翻譯這篇文章的目的不是讓人了解Qt,而是讓人試著學(xué)習(xí)點(diǎn)C++編程的軟技能。我從原文中得到的一些風(fēng)格上的體會,也希望你能從中有所收獲.(譯者注)
我們在Trolltech做了大量研究來改進(jìn)Qt開發(fā)體驗(yàn).在這篇文章中,我將分享我們的一些成果,呈現(xiàn)我們在進(jìn)行Qt 4設(shè)計(jì)時(shí)所使遵循的原現(xiàn),并向你展示如何將它們應(yīng)用到你的代碼中.

設(shè)計(jì)應(yīng)用程序接口(APIs)是有難度的.它是像跟設(shè)計(jì)編程語言一樣困難的藝術(shù).要遵循許多不同的的原則,這些原則中的許多還彼此沖突.

現(xiàn)今的計(jì)算機(jī)教育過多關(guān)注于算法和數(shù)據(jù)結(jié)構(gòu),很少去關(guān)注隱藏在程序設(shè)計(jì)語言和程序框架后面的那些設(shè)計(jì)原則.這使得程序員們面對日益重要的任務(wù),創(chuàng)建可復(fù)用的組件,毫無準(zhǔn)備.

在面向?qū)ο笳Z言出現(xiàn)前,通用的可復(fù)用的代碼大都由庫提供者而不是應(yīng)用程序開發(fā)者來編寫.在Qt世界中,這種情況已發(fā)生了很大的變化.在用Qt編程其實(shí)就是在寫新的組件.典型的Qt應(yīng)用程序都存在某些自定義的組件,在整個(gè)應(yīng)用程序中被復(fù)用.相同的組件常常作為其他程序的一部分被開發(fā)出來.KDE,K桌面環(huán)境,甚至使用許多附加庫,來進(jìn)一步擴(kuò)展Qt,實(shí)現(xiàn)許多額外的類.

但是一個(gè)優(yōu)秀,高效的C++ API究竟是怎樣子呢?它的好壞取決于許多因素,比如說,手頭上的任務(wù)和特定目標(biāo)群體.優(yōu)秀的API具有很多特性,它們的一些是普遍所要期望的,另一些是針對特定問題域的.

優(yōu)秀API的六個(gè)特性

API對于程序員就相當(dāng)于GUI對于最終用戶.API中'P'代表程序員(Programmer),而不是程序(Program),強(qiáng)調(diào)這一點(diǎn)是為了說明API是讓程序員使用的,程序員是人而不機(jī)器.

我們認(rèn)為APIs應(yīng)當(dāng)精簡而完備,具有清晰簡單的語義,直觀,易記且應(yīng)使代碼具有可讀性.

  • 精簡性:精簡的API具有盡可能少的類和公共成員.這使得理解,記憶,調(diào)試,更改API更加容易.
  • 完備性:完備的API意味著擁有應(yīng)具有的期望功能.這可能使與API保持精簡性相沖突.還有,如果成員函數(shù)放在不相匹配的類中,那么許多使用這個(gè)功能函數(shù)的潛在用戶會找不到它.
  • 清晰簡單的語義:正如與其他設(shè)計(jì)工作一樣,你應(yīng)該準(zhǔn)守最小驚議原則.讓通常的任務(wù)簡單,罕見的任務(wù)應(yīng)盡可能簡單,但它不應(yīng)成為重點(diǎn).解決特定的問題.不要使解決方法具有普適作用,當(dāng)它們不需要的時(shí)候.
  • 直觀性:與計(jì)算機(jī)有關(guān)的其他事情一樣,API應(yīng)具有直觀性.不同經(jīng)歷和背景會導(dǎo)致對哪些是直觀,哪些不是直觀的不同看法.如果對非專業(yè)的用戶在不需要閱讀文檔下能立即使用API,或?qū)@個(gè)API不了解的程序員能理解使用了API的代碼,那么這API就是具有直觀性.
  • 易記:為了使API容易記憶,使用一致且精準(zhǔn)的命名規(guī)范.使用容易識別的模式和概念,避免使用縮寫.
  • 能生成可讀生代碼:代碼只寫一遍,卻要閱讀許多遍(調(diào)試或更改).可讀性的代碼有時(shí)候可能需要多敲些字,但是從產(chǎn)品生命周期中可節(jié)省很多時(shí)間.

最后,請記住:不同的用戶使用API的不同部分.當(dāng)簡單地使用Qt類的實(shí)例可能有直觀性,但這有可能使用戶在閱讀完有關(guān)文檔后,才能嘗試使用其中部分功能.

方便性陷阱

通常的誤讀是越少的代碼越能使你達(dá)到編寫更好的API這一目的.請記住,代碼只寫一遍,卻要一遍又一遍地去理解閱讀它.比如:

QSlider *slider = new QSlider(12, 18, 3, 13, Qt::Vertical,
                                  0, "volume");

可以會比下面的代碼更難閱讀(甚至于編寫)

QSlider *slider = new QSlider(Qt::Vertical);
slider->setRange(12, 18);
slider->setPageStep(3);
slider->setValue(13);
slider->setObjectName("volume");

布爾參數(shù)陷阱

布爾參數(shù)常常導(dǎo)致難以閱讀的代碼.特別地,增加某個(gè)bool參數(shù)到現(xiàn)存的函數(shù)一般都會是個(gè)錯(cuò)誤的決定.在Qt中,傳統(tǒng)的例子是repaint(),它帶有一個(gè)可選的布爾參數(shù),來指定背景是否刪除(默認(rèn)是刪除).這就導(dǎo)致了代碼會像這樣子:

widget->repaint(false);

初學(xué)者可能會按字面義理解為,"不要重繪!"

自然的想法是bool參數(shù)節(jié)省了一個(gè)函數(shù),因此減少了代碼的臃腫.事實(shí)上,這增加了代碼的臃腫,有多少Q(mào)t用戶真正知道下面這三行代碼在做什么呢?

widget->repaint();
widget->repaint(true);
widget->repaint(false);

好一點(diǎn)的API代碼可能看起來像這樣:

widget->repaint();
widget->repaintWithoutErasing();

在Qt 4中,我們解決這個(gè)問題的辦法是,簡單地去除掉不刪除widget而進(jìn)行重繪的可能性.Qt 4對雙重緩沖的原生支持,會使這功能被廢棄掉.

這里有些例子:

widget->setSizePolicy(QSizePolicy::Fixed,
                          QSizePolicy::Expanding, true);
textEdit->insert("Where's Waldo?", true, true, false);
QRegExp rx("moc_*.c??", false, true);

顯然的解決辦法就是將bool 參數(shù)用枚舉類型來替換.這就是我們在Qt 4中Qstring中的大小寫敏感所做的,比較下面兩個(gè)例子:

str.replace("%USER%", user, false);               // Qt 3
str.replace("%USER%", user, Qt::CaseInsensitive); // Qt 4

靜態(tài)多態(tài)

相似的類應(yīng)該有相似的API.在某種程度上,這能用繼承來實(shí)現(xiàn),也就是運(yùn)用運(yùn)行時(shí)多態(tài)機(jī)制.但是多態(tài)也能發(fā)生在設(shè)計(jì)時(shí).比如,你將QListBox與QComboBox交換,QSlider與QSpinBox交換,你會發(fā)現(xiàn)API的相似性會使這種替換變得比較容易.這就是我們所謂的"靜態(tài)多態(tài)".

靜態(tài)多態(tài)也能使記憶API和編程模式更加容易.因而,對一組相關(guān)類的相似API有時(shí)候比為每個(gè)類設(shè)計(jì)獨(dú)特完美的API會更好.

命名藝術(shù)

命名有時(shí)候是設(shè)計(jì)API中最重要的事情了.某個(gè)類應(yīng)叫什么名字,某個(gè)成員函數(shù)又應(yīng)叫什么名字,都需要好好思考.?

通常的命名規(guī)則

有少許規(guī)則對所有類型的命名都適應(yīng).首先,正如我早先所提到的,不要用縮寫.甚至對用"prev"代表"previous"這樣明顯的縮寫也不會在長期中受益,因?yàn)橛脩舯仨氂涀∧男┟质强s寫.

如果連API自身都不能保持統(tǒng)一,事情自然會變得更壞.比如,Qt 3中有activatePreviousWindow()函數(shù),也有fetchPrev()函數(shù).堅(jiān)持"沒有縮寫"這條規(guī)則,會使創(chuàng)建一致的API更加簡單.

在設(shè)計(jì)類中,另一重要但是不明顯的規(guī)則是盡量保持子類中名字的簡潔易懂.在Qt 3中,這個(gè)原則并不總是被遵守.為了說明這一點(diǎn),我們舉下QToolButton的例子.如果你在Qt 3中對QToolButton調(diào)用call name(), caption(), text(), 或 textLabel()成員函數(shù)時(shí),你希望會發(fā)生什么?那就在Qt設(shè)計(jì)器中試試QToolButton吧.

  • name 屬性繼承自QObject,用來在調(diào)試和測試中指代對象的內(nèi)部名稱.
  • caption 屬性繼承自QWidget,指代窗體的標(biāo)題.對于QToolButton沒有什么意思,既然它們都是由父窗體創(chuàng)建的.
  • text 屬性繼承自QButton,通常用于按鈕中,除非useTextLabel為真.
  • textLabel 屬性 在QToolButton中聲明,如果useTextLabel為真,則顯示在按鈕上.

為了可讀性的關(guān)系,在Qt4中name 被稱為objectName ,caption被稱為windowTitle,在QToolButton中為了使text明晰,不再有textLabel屬性.

命名類

不應(yīng)為每個(gè)不同的類尋求完美的名字,而是將類進(jìn)行分給.比如,在Qt 4中所有跟模型有關(guān)的視類的部件都用View后綴(QlistView,QTableView,QTreeView),相應(yīng)的基于部件的類用Widget后綴代替(QListWidget,QTableWidget,QTreeWidge).

枚舉類型和值類型命名

當(dāng)設(shè)計(jì)枚舉時(shí),我們應(yīng)當(dāng)記住C++中(不像Java或C#),枚舉值在使用時(shí)不帶類型名.下面的例子說明了對枚舉值取太一般化的名字的危害:

namespace Qt
{
    enum Corner { TopLeft, BottomRight, ... };
    enum CaseSensitivity { Insensitive, Sensitive };
    ...
};
    
    tabWidget->setCornerWidget(widget, Qt::TopLeft);
    str.indexOf("$(QTDIR)", Qt::Insensitive);

在上面這行中,Insensitive這個(gè)名字什么意思呢?為枚舉類型命名具有指導(dǎo)的原則是最好在每個(gè)枚舉值中重復(fù)枚舉類型的名字.

namespace Qt
{
    enum Corner { TopLeftCorner, BottomRightCorner, ... };
    enum CaseSensitivity { CaseInsensitive,
                              CaseSensitive };
    ...
};
    
tabWidget->setCornerWidget(widget, Qt::TopLeftCorner);
str.indexOf("$(QTDIR)", Qt::CaseInsensitive);
    

但枚舉值之間是一種"或"關(guān)系和被用作標(biāo)志位時(shí),傳統(tǒng)的解決方法是將"或"結(jié)果存為int,這樣做是類型不安全的.Qt 4提供了一模板類QFlags<T>,其中T是枚舉類型.Qt為標(biāo)志類型名稱提供了便利,你能用Qt::Alignment 來代替QFlags<Qt::AlignmentFlag>.

為了方便,我們給枚舉類型單數(shù)形式的名稱(只有當(dāng)只含一個(gè)標(biāo)志位時(shí)),給"flags"類型復(fù)數(shù)形式的名稱,比如:

enum RectangleEdge { LeftEdge, RightEdge, ... };
typedef QFlags<RectangleEdge> RectangleEdges;
    

在某些情況下,"flags"類型有單數(shù)形式的名稱.在這種情況下,枚舉類型以Flag后綴標(biāo)識:

enum AlignmentFlag { AlignLeft, AlignTop, ... };
typedef QFlags<AlignmentFlag> Alignment;

函數(shù)和參數(shù)的命名

函數(shù)命名中的一條規(guī)則就是應(yīng)能從它的名字清楚地看出函數(shù)是否著副作用.在Qt 3中,常函數(shù)QString::simplifyWhiteSpace()就違反了這規(guī)則.即然它返回QString,而不是像它的名字所表述的那樣修改字符串. 在Qt 4中,這個(gè)函數(shù)被重命名為QString::simplified().

參數(shù)名對于程序員來說是重要的信息來源,即使它們不出現(xiàn)在調(diào)用API的代碼中.既然現(xiàn)代的IDE會在程序員編碼時(shí)顯示這些參數(shù),所以非常值得在頭文件中給這些參數(shù)取恰當(dāng)?shù)拿郑谖臋n中同樣使用相同的名字

給布爾型的getter,setter,屬性的命名

給布爾型的getter,setter,屬性取個(gè)恰當(dāng)?shù)拿挚偸翘貏e困難.getter應(yīng)該叫checked() 或者還是叫isChecked(),取scrollBarsEnabled()還是areScrollBarEnabled()

在Qt 4中,我們對于getter的函數(shù)使用下面的指導(dǎo)原則

  • 形容詞就使用is-前綴.比如:
    • isChecked()
    • isDown()
    • isEmpty()
    • isMovingEnabled()
    但是形容詞應(yīng)用到復(fù)數(shù)形式的名詞沒有前綴:
    • scrollBarsEnabled(), not areScrollBarsEnabled()
  • 動(dòng)詞沒有前綴,也不使用第三人稱的(-s):
    • acceptDrops(), not acceptsDrops()
    • allColumnsShowFocus()
  • 名詞性的通常沒有前綴:
    • autoCompletion(), 不用isAutoCompletion()
    • boundaryChecking()
    有時(shí)候沒有前綴會產(chǎn)生誤導(dǎo),在這種情就加上前綴is-:
    • isOpenGLAvailable(), not openGL()
    • isDialog(), not dialog()
    (如果函數(shù)叫做dialog(),我們通常會認(rèn)定它會返回QDialog*類型)

setter的命名可以從這推知,只要去掉is前綴,在名字前面加set前綴就可以了.比如setDown()setScrollBarsEnabled().屬性的名字跟getter一樣,就是沒有is前綴

指針或引用?

對于向外傳參,是使用指針,還是引用更好呢?

void getHsv(int *h, int *s, int *v) const
void getHsv(int &h, int &s, int &v) const

絕大多數(shù)C++書籍都推薦無論何時(shí)都盡可能使用引用,因?yàn)閺拇蠖鄶?shù)情況來說,引用比指針有著所謂的"安全和優(yōu)雅".相比而方,在Trolltech,我們更趨向于指針,因?yàn)樗褂脩舸a更具可讀性.比較下面的代碼:

color.getHsv(&h, &s, &v);
color.getHsv(h, s, v);

只有第一行代碼能更清楚地說明h,s,v在函數(shù)被調(diào)用后,其值極有可能被修改.

案例分析:QProgressBar

為了在實(shí)際代碼中說明這些概念,我們以QProgressBar在Qt3和Qt4中的比較進(jìn)行研究.在Qt 3中:

class QProgressBar : public QWidget
{
  ...
    public:
        int totalSteps() const;
        int progress() const;
    
        const QString &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 &progressStr,
                                  int progress,
                                  int totalSteps);
        ...
    };
    

對這個(gè)API進(jìn)行改進(jìn)的關(guān)鍵之處就是需要觀察到Qt 4中QProgressBar與QAbstractSpinBox,以及它的子類,QSpinBox,QSlider,和QDial有著相似性.解決的辦法呢?將其中的progress和totalSteps用minimun,maximum和value替換.

增加valueChanged()的信號量.增加setRange()這一方便的函數(shù).

接下來需要到progressString, percentageindicator實(shí)際上都指代同一東西:顯示在進(jìn)度欄上的文本.通常這一文本是一百分?jǐn)?shù),但是它能被setIndicator()設(shè)置成任何值.這里是新的API:

virtual QString text() const;
void setTextVisible(bool visible);
bool isTextVisible() const;

默認(rèn),這文本是百分比指示器.這可以用重新實(shí)現(xiàn)的text()進(jìn)行改變.

在Qt 3中,setCenterIndicator()setIndicatorFollowsStyle()是兩個(gè)影響對齊方式的函數(shù).它們現(xiàn)在都被一個(gè)高級的函數(shù)所取代,setAlignment()

void setAlignment(Qt::Alignment alignment);

如果程序員沒有調(diào)用 setAlignment(),對齊是基于的樣式?jīng)Q定的.對于Motif樣式,文本顯示在中間,而對于其他樣式,文本是右對齊的.

這里是改進(jìn)過的QProgressBar:

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);
        ...
};

怎樣寫出正確的APIs

APIs需要質(zhì)量保證.最早的版本一般都不是很好的,你必須測試它.通過調(diào)用這個(gè)API的代碼作為測試事例,來驗(yàn)證代碼具有可讀性.

另外的技巧包括讓人在沒有文檔和類文檔化(類的概述和函數(shù)說明)的情況下能夠使用這個(gè)API.

當(dāng)你陷入麻煩中時(shí),文檔化也是好的辦法找出一個(gè)合適的命名:試著為這些類,函數(shù),枚舉值標(biāo)住文檔,然后使用浮現(xiàn)在你腦中的第一個(gè)詞匯.如果你找不到精準(zhǔn)的名字去表述,那很有可能這個(gè)東西就不應(yīng)存在.如果任何辦法都失敗了,而且你確信這個(gè)概念是有用的,那就發(fā)明一個(gè)新的名字吧.最后,不管怎么說,"widget", "event", "focus", and "buddy"這些詞總會能用上一個(gè).



len 2008-05-11 20:07 發(fā)表評論
]]>
Say Hello to Gladehttp://m.shnenglu.com/len/archive/2008/03/27/45548.htmllenlenThu, 27 Mar 2008 12:49:00 GMThttp://m.shnenglu.com/len/archive/2008/03/27/45548.htmlhttp://m.shnenglu.com/len/comments/45548.htmlhttp://m.shnenglu.com/len/archive/2008/03/27/45548.html#Feedback7http://m.shnenglu.com/len/comments/commentRss/45548.htmlhttp://m.shnenglu.com/len/services/trackbacks/45548.htmlGlade是針對GTK+工具箱與GNOME桌面開發(fā)環(huán)境的快速圖形界面開發(fā)工具.用Glade設(shè)計(jì)的用戶接口以XML的文件形式保存,然后根據(jù)需要由程序通過libglade庫文件來動(dòng)態(tài)加載.因?yàn)槭褂昧薼ibglade庫,Glade XML文件能夠被C,C++,Java,Perl,Python,C#等等語言所支持.針對其他未涉及的語言的支持也是方便的.

在網(wǎng)上可以見到某些關(guān)于Glade的教程,大都是關(guān)于Linux平臺和Glade 2的,因?yàn)樵菺lade作為快速開發(fā)工具,集成代碼生成功能,生成C文件.所以常常有初學(xué)者對網(wǎng)上某些教程所提及的"generate"(生成代碼)功能表示迷惑,在新版本的Glade-3上找不到對應(yīng)的功能.

新版本的Glade-3是對原先Glade代碼的完全重寫.一個(gè)顯著的變化就是去除了代碼生成功能.這樣做是有原因的,即然代碼生成功能不被提倡使用,而是更鼓勵(lì)使用libglade功能.但是如果你真需要代碼生成功能的話,它還是可以做為插件來提供的.另一個(gè)顯著的不同是glade-3設(shè)計(jì)用來最大化使用GObject的自省機(jī)制(GObject introspection),來使外部工具箱和部件的控制,信號和屬性的集成更加容易.

如果看過Say Hello to GTK+的話,可能感覺那樣的窗體程序太簡單了.那么現(xiàn)在讓我們借助Glade弄點(diǎn)兒復(fù)雜一點(diǎn)兒的界面吧.首先來瞧瞧Glade長什么樣,下圖就是Glade在windows下的界面.左邊的窗體的小部件選擇器,相當(dāng)于調(diào)色板.中間是主菜單,右邊的是屬性窗體.

glade_win

現(xiàn)在開始創(chuàng)建一個(gè)類似于文本編輯器的圖形界面.按照上圖標(biāo)注的順序,依次添加window部件,vertical box部件,menu bar部件,text view部件和Status部件.vertical box設(shè)置三行,它是用來進(jìn)行界面布局,分割空間用,這是gtk+設(shè)計(jì)與傳統(tǒng)的windows UI設(shè)計(jì)很不同的地方.后三個(gè)部件是放置vertical box中的,最后設(shè)計(jì)完成圖形如下.保存取名為win.glade.如果你感興趣的話,可以用文件編輯器打開這個(gè)文件看看,正如所說的那樣,它是一個(gè)xml格式的文本文件.

win

現(xiàn)在我們設(shè)置相關(guān)的頭文件和庫文件,編輯一個(gè)glade.c文件,添加進(jìn)以下的代碼,運(yùn)行看看,會出現(xiàn)如上圖的對話框.雖然這個(gè)對話框什么都不干,但是通過Glade,我們能較為容易地設(shè)計(jì)界面,而不用通過gtk函數(shù),一個(gè)一個(gè)將控件實(shí)現(xiàn).

#include <gtk/gtk.h>
#include <glade/glade.h> int main(int argc, char* argv[]) { GladeXML *gxml; GtkWidget *window; gtk_init (&argc, &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; }


len 2008-03-27 20:49 發(fā)表評論
]]>
Say Hello to GTK+http://m.shnenglu.com/len/archive/2008/03/23/45190.htmllenlenSun, 23 Mar 2008 07:18:00 GMThttp://m.shnenglu.com/len/archive/2008/03/23/45190.htmlhttp://m.shnenglu.com/len/comments/45190.htmlhttp://m.shnenglu.com/len/archive/2008/03/23/45190.html#Feedback3http://m.shnenglu.com/len/comments/commentRss/45190.htmlhttp://m.shnenglu.com/len/services/trackbacks/45190.htmlWindows下的C++程序員在開發(fā)圖形用戶界面時(shí),首先想到可能就是MFC了.對于GTK+這種GNU/Linux上出生出來的東西,就感到陌生了.GTK+是類似于MFC的圖形界面庫,跟MFC不同的是,它不是用C++,而是用C語言實(shí)現(xiàn)了面對對象的機(jī)制,但能與許多語言綁定,并具有跨平臺的特性.比如與Python的結(jié)合,就產(chǎn)生初識PyGTK"就介結(jié)了其在Windows平臺的安裝.

在Windows開發(fā)GTK+的應(yīng)用程序,首先需要其在Windows版本下的庫文件,下載gladewin32項(xiàng)目中的gtk+-win32-devel安裝包進(jìn)行安裝.我這里使用VS2005進(jìn)行配置,因?yàn)橄鄬τ谄渌沫h(huán)境,大家對于此IDE更為熟悉.接下來我將一步步介紹我在對GTK/Glande3說Hello時(shí)碰到的問題與解決方法.

丑陋的Hello World

任何像我一樣急切的人,都希望用最少的代碼,看一下GTK+的世界是怎么樣的.新建一"Win32 項(xiàng)目",然后向其添加gtk.c文件.

/*  file gtk.c  */ 
#include  < gtk / gtk.h > 

int  main( int  argc,  char *  argv[])
{
    GtkWidget *  window;
    gtk_init ( & argc,  & 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 ;
} 

現(xiàn)在麻煩的事情到了,設(shè)置相關(guān)的頭文件和庫文件.設(shè)置頭文件,右鍵點(diǎn)擊項(xiàng)目名,然后選擇屬性.然后在"常規(guī)"-"附加包含目錄"中設(shè)置你安裝gtk+-win32-devel時(shí)對應(yīng)的頭文件目錄.然后再設(shè)置庫文件,需要gtk-win32-2.0.lib,glib-2.0.lib,gobject-2.0.lib.

p1_4.jpg
p2_thumb.jpg p3_thumb.jpg

設(shè)置完好后,你就可以編譯運(yùn)行了,一個(gè)什么都不干的丑陋的windows窗體出現(xiàn)你面前了.若編譯不通過,缺少某些頭文件的話,查看出錯(cuò)信息,然后用windows查找對應(yīng)頭文件路徑,再設(shè)置.若連接出錯(cuò),很可能在設(shè)置庫文件出錯(cuò)了,同理,設(shè)置相應(yīng)的庫文件路徑.程序代碼很簡單,定義一個(gè)windows窗體指針,然后創(chuàng)建窗體和定義窗體標(biāo)題,接著就是顯示了,和gtk主循環(huán)了.

p4_2.jpg

讓GTK+有點(diǎn)知覺

或許你發(fā)現(xiàn)了,點(diǎn)擊窗體中的"X"關(guān)閉按鈕,雖然窗體消失了,但是黑色的命令窗口還在,發(fā)現(xiàn)"任務(wù)管理器"中程序還在運(yùn)行著.對,它并沒有像你想的那樣,在點(diǎn)擊"X"關(guān)閉按鈕結(jié)束掉程序.這些是需要你告訴程序該怎么做的.我們需要在代碼中添加相應(yīng)的事件處理函數(shù). 新增加了destroy函數(shù),它就是事件處理函數(shù),在gtk也可叫做信號處理函數(shù),因?yàn)間tk中用信號來進(jìn)行事件的通知.destory函數(shù)的形參是有約定寫法的,這個(gè)大家可以參見具體的手冊.在主程序中,還需要將這一函數(shù)與具體的信號進(jìn)行關(guān)聯(lián),見第17行.

在完成這些工作后,你再點(diǎn)擊"X"按鈕時(shí),會發(fā)現(xiàn)"命令行窗口"會出現(xiàn)"按任意鍵繼續(xù)",程序是真正地退出了.

/* file gtk.c */
#include 
static void destroy( GtkWidget *widget,
                    gpointer   data )
{
    gtk_main_quit ();            //退出gtk主循環(huán)
}

int main(int argc, char* argv[])
{

    GtkWidget* window;
    gtk_init (&argc, &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;
}

讓黑黑的命令行窗口消失

有些人會對這個(gè)gtk應(yīng)用程序總會伴隨著黑黑的命令行窗口感到不爽,包括我自己在內(nèi).不知道gtk程序在gnome下也是這樣,我沒有試過,不知道.現(xiàn)在我就使用windows平臺的特定方法,來讓它消失吧,就是使用WinMain做為主函數(shù).這方法或許不是最正規(guī)的做法,但我看來卻有效.如果要考慮到跨平臺的話,可以用條件編譯處理下.

/* file gtk.c */
#include 
#include 
static void destroy( GtkWidget *widget,
                    gpointer   data )
{
    gtk_main_quit ();            //退出gtk主循環(huán)
}

int WinMain(HINSTANCE hInstance,
            HINSTANCE hPrevInstance,
            LPSTR lpCmdLine,
            int nCmdShow
            )
{
    //為應(yīng)付gtk_init所需要的參數(shù)
    int argc=1;    
    char* commandLine={"gtkApplication"};
    char** argv = &commandLine;

    GtkWidget* window;
    gtk_init (&argc, &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;
}

好啦,現(xiàn)在再編譯運(yùn)行,命令行窗口沒有了.你會發(fā)現(xiàn)真正的win32窗體了.但是在開發(fā)中,我建議用gtk時(shí),還是讓命令行窗口顯示出來,因?yàn)間tk在出錯(cuò)時(shí),會把一些有用的信息打到命令行窗口中,這對你的幫助會很大.



len 2008-03-23 15:18 發(fā)表評論
]]>
初識PyGTKhttp://m.shnenglu.com/len/archive/2008/03/12/44296.htmllenlenWed, 12 Mar 2008 11:43:00 GMThttp://m.shnenglu.com/len/archive/2008/03/12/44296.htmlhttp://m.shnenglu.com/len/comments/44296.htmlhttp://m.shnenglu.com/len/archive/2008/03/12/44296.html#Feedback0http://m.shnenglu.com/len/comments/commentRss/44296.htmlhttp://m.shnenglu.com/len/services/trackbacks/44296.html

PyGTK讓你用Python輕松創(chuàng)建具有圖形用戶界面的程序.底層的GTK+提供了各式的可視元素和功能,如果需要,你能開發(fā)在GNOME桌面系統(tǒng)運(yùn)行的功能完整的軟件.

PyGTK真正具有跨平臺性,它能不加修改地,穩(wěn)定運(yùn)行各種操作系統(tǒng)之上,如Linux,Windows,MacOS等.除了簡單易用和快速的原型開發(fā)能力外,PyGTK還有一流的處理本地化語言的獨(dú)特功能.

PyGTK是自由軟件,所以你能幾乎沒有任何限制的使用,修改,分發(fā),研究它,它是基于LGPL協(xié)議發(fā)布的.

如果你對上面提到的GTK+,也不了解的話,那允許再對它也進(jìn)行一番介紹.GTK+,用C語言開發(fā)的,具有跨平臺的GUI庫,它是GNOME桌面系統(tǒng)(如果你在用Linux,一定不陌生)和GIMP圖象編輯器的開發(fā)工具箱.它是世界上許多程序員的選擇,對他們來說,國際化的支持是必要的,而且性能也總是他們考慮的因素.與GTK同一領(lǐng)域的還有Qt庫,它是由商業(yè)公司開發(fā)的C++圖形庫,雖然它也有免費(fèi)的.

在windows平臺的安裝和開發(fā)

安裝PyGTK只需執(zhí)行下列步驟:

  • 安裝Python2.4或以上的windows版本[www.python.org]
  • 從GTK+/Glade的windows版本的GTK+ 2.10開發(fā)運(yùn)行時(shí)環(huán)境[gladewin32.sourceforge.net]
  • 從PyGTK網(wǎng)站下載安裝PyCairo,PyGobject和PyGTK安裝包,注意這些需全部安裝才能使PyGTK工作[pygtk.org]

或許你對這些步驟還感到麻煩,或者對Python不熟悉的話,那也沒有關(guān)系,直接下載一鍵安裝包all-in-one installer,為你配置好全部運(yùn)行時(shí)環(huán)境.

看看開發(fā)環(huán)境是否配置正確,將下列代碼作為Python腳本或者在Python交互控制臺下輸入.如果正確的話,應(yīng)該有一個(gè)標(biāo)題為"Hello World"的windows的空窗口呈現(xiàn)在你面前.

如果不能運(yùn)行的話,有可能會出現(xiàn)一個(gè)不能成功加載dll的錯(cuò)誤提示,這是因?yàn)槿鄙賗conv.dll.這時(shí)需要只需從網(wǎng)上下載過來,拷貝至windows/system32目錄下即可了.

import gtk
window = gtk.Window()
window.set_title("Hello World")
window.show_all()

gtk.main()


len 2008-03-12 19:43 發(fā)表評論
]]>
PC-linthttp://m.shnenglu.com/len/archive/2008/01/30/42222.htmllenlenWed, 30 Jan 2008 07:18:00 GMThttp://m.shnenglu.com/len/archive/2008/01/30/42222.htmlhttp://m.shnenglu.com/len/comments/42222.htmlhttp://m.shnenglu.com/len/archive/2008/01/30/42222.html#Feedback0http://m.shnenglu.com/len/comments/commentRss/42222.htmlhttp://m.shnenglu.com/len/services/trackbacks/42222.htmlPC-lint for C/C++是由Gimpel軟件公司于1985年開發(fā)的代碼靜態(tài)分析工具,它能有效地發(fā)現(xiàn)程序語法錯(cuò)誤、潛在的錯(cuò)誤隱患、不合理的編程習(xí)慣等。

FlexeLint for C/C++是在PC_lint在windows平臺獲得成功后,同樣由Gimpel公司開發(fā)的,以源代碼形式發(fā)布的,在Unix/Linux平臺上的靜態(tài)代碼分析工具。

本文主要介紹PC-lint的安裝與配置,因此是在windows平臺上進(jìn)行討論。

PC-lint支持幾乎所有流行的編譯器和IDE環(huán)境,可能因?yàn)槠浒l(fā)展歷史和面對專業(yè)程序員群體的原因,它是以命令行加配置文件的形式進(jìn)行使用,所以其使用習(xí)慣跟現(xiàn)在常見的windows軟件不同。

現(xiàn)以PC-lint與VS2005進(jìn)行集成來說明:

將PC-lint釋放到某一目錄下,如:D:\Program Files\pclint.將新建一std.lnt文件在主目錄中,并將添加上以下的內(nèi)容

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"

注意:-i后面為相應(yīng)的vc頭文件目錄路徑,而一系列xxx.lnt是語法配置規(guī)則,決定了按什么規(guī)則進(jìn)行檢查,以后可以根據(jù)需要進(jìn)行增減. 寫在配置文件中相應(yīng)的的xxx.lnt從lnt子目錄中,拷貝到主目錄中.(這一步很重要) 在vs2005中的工具->外部工具中,點(diǎn)擊"添加",新建一個(gè)外部工具.標(biāo)題可以任意,可取(pc_lint);命令為:D:\Program Files\pclint\LINT-NT.EXE;參數(shù)為:-i"D:\Program Files\pclint" std.lnt "$(ItemFileName)$(ItemExt)";初始目錄為:$(ItemDir),并將下面的"使用輸出窗口"勾選上. 接下來,就可以寫一段程序,在工具菜單中選擇pc_lint 來進(jìn)行檢查了.如果你編寫的程序有不符合定義的規(guī)范,則會在輸出窗口中出現(xiàn)相關(guān)的信息.



len 2008-01-30 15:18 發(fā)表評論
]]>
人人狠狠综合久久亚洲婷婷 | 精品无码久久久久久久动漫| 久久久久久久97| 久久久无码精品亚洲日韩京东传媒| 久久精品视频一| 久久精品亚洲精品国产色婷| 国产精品久久久久无码av| 国产激情久久久久影院小草| 亚洲精品乱码久久久久久按摩| 久久国产乱子伦精品免费午夜| 午夜精品久久久久久久| 色综合色天天久久婷婷基地| 精品国产一区二区三区久久蜜臀| 一本色道久久综合狠狠躁| 国内精品久久久久久久涩爱| 久久久久波多野结衣高潮| 亚洲国产精品久久久久久| 久久久久人妻精品一区| 久久久无码精品午夜| 久久av高潮av无码av喷吹| 无码人妻久久一区二区三区免费| 久久精品一区二区三区中文字幕| 国产精品对白刺激久久久| 久久久一本精品99久久精品66| 久久久亚洲精品蜜桃臀| 国产一久久香蕉国产线看观看| 久久免费的精品国产V∧| 久久亚洲精品国产亚洲老地址 | 久久一本综合| 国产一区二区精品久久| 久久久免费精品re6| 中文字幕久久久久人妻| 伊人久久大香线蕉综合5g| 亚洲精品国精品久久99热| 国产精品熟女福利久久AV| www.久久热.com| 99久久无色码中文字幕| 99久久免费国产精品热| 久久97精品久久久久久久不卡| .精品久久久麻豆国产精品| A狠狠久久蜜臀婷色中文网|