目中的安裝與集成實(shí)踐)
簡(jiǎn)介這份DevExpress 14.1.3 for D7-XE7組件包面向使用Delphi 7及XE7的桌面與移動(dòng)端開(kāi)發(fā)者是一套包含數(shù)據(jù)網(wǎng)格、圖表、報(bào)表、菜單、工具欄、對(duì)話框等常見(jiàn)VCL控件的成熟第三方組件庫(kù)能顯著提升界面開(kāi)發(fā)效率與數(shù)據(jù)展示效果。Delphi 7是經(jīng)典的Windows可視化開(kāi)發(fā)工具XE7則加入iOS/Android跨平臺(tái)支持該版本同時(shí)兼容兩者適用范圍廣。壓縮包為7z格式整體約190MB內(nèi)含主安裝程序以及附送的DEV漢化Demo便于中文用戶對(duì)照理解控件屬性和事件用法目前文件分類明細(xì)未額外提供但安裝后即可在IDE中集成使用。已有134人學(xué)習(xí)下載適合為老版本Delphi項(xiàng)目引入成熟控件體系或借助漢化示例快速上手的中高級(jí)開(kāi)發(fā)者。該組件基于原生代碼實(shí)現(xiàn)運(yùn)行高效支持?jǐn)?shù)據(jù)綁定和多種預(yù)設(shè)主題可幫助開(kāi)發(fā)者減少重復(fù)設(shè)計(jì)構(gòu)建外觀統(tǒng)一、交互流暢的專業(yè)應(yīng)用。1. 版本選型與適用場(chǎng)景分析1.1 為什么今天還要聊14.1.3說(shuō)起DevExpress VCLDelphi圈子里應(yīng)該沒(méi)人陌生而14.1.3這個(gè)版本對(duì)不少老工程師來(lái)說(shuō)既是一道坎也是一個(gè)寶。我手上維護(hù)的幾個(gè)老系統(tǒng)業(yè)務(wù)邏輯全跑在Delphi 7上界面卻年年要升級(jí)——工具欄要換膚、表格要有篩選、列表要支持拖拽客戶還總拿它跟各種新軟件比。DevExpress VCL 14.1.3就是在這種處境下被我反復(fù)選中的版本。它能在D7到XE7之間無(wú)縫銜接整個(gè)工程遷移過(guò)去不用重寫控件層這在組件界相當(dāng)難得。為什么不用更新的版本原因很直接DevExpress從15.x開(kāi)始逐步收緊對(duì)老IDE的支持15.2雖然還能勉強(qiáng)裝進(jìn)D7但已經(jīng)出現(xiàn)設(shè)計(jì)器不穩(wěn)定、編譯出來(lái)的DCU體積異常等問(wèn)題到16.x干脆正式移除了D7和2007的支持。所以只要是還堅(jiān)持留在D7的老項(xiàng)目14.1.3基本就是最合理的落點(diǎn)。它覆蓋Delphi 7、2005、2009、2010、XE、XE2、XE3、XE4、XE5、XE6、XE7整條產(chǎn)品線恰恰橫跨了從AnsiString到UnicodeString的完整過(guò)渡期這在選型時(shí)是個(gè)非常重要的加分項(xiàng)。1.2 D7到XE7的兼容矩陣不同IDE版本編譯出的DCU文件是互不兼容的DevExpress的做法是每個(gè)版本單獨(dú)出一套DCU和BPL。下面這張表是我實(shí)際整理過(guò)的兼容情況方便你判斷自己該用哪個(gè)安裝模式IDE版本字符串類型Win32/Win6414.1.3支持度建議DCU目錄Delphi 7AnsiStringWin32完整支持Sources\D7\Delphi 2007AnsiStringWin32完整支持Sources\D2007\Delphi 2009UnicodeStringWin32完整支持Sources\D2009\Delphi XE2UnicodeStringWin32/Win64完整支持Sources\DXE2\Delphi XE7UnicodeStringWin32/Win64完整支持Sources\DXE7\如果一臺(tái)機(jī)器上同時(shí)裝了D7和XE7安裝器會(huì)分別檢測(cè)并注冊(cè)各自的設(shè)計(jì)期包兩個(gè)IDE互不干擾。但要注意工程文件里的搜索路徑必須跟IDE版本一一對(duì)應(yīng)不能圖省事讓D7去用XE7的DCU否則編譯時(shí)報(bào)的“F2613 DCU版本不匹配”會(huì)讓你懷疑人生這一點(diǎn)在后面的排查章節(jié)我會(huì)專門展開(kāi)。2. 安裝部署全流程2.1 安裝前的系統(tǒng)檢查裝DevExpress VCL之前一定先確認(rèn)三件事。第一把正在運(yùn)行的Delphi IDE全部關(guān)掉包括BDS、bds.exe的進(jìn)程設(shè)計(jì)期包注冊(cè)時(shí)要往IDE里寫注冊(cè)表IDE占用著文件會(huì)導(dǎo)致注冊(cè)失敗。第二殺毒軟件最好暫時(shí)退出或者至少把安裝目錄加入白名單14.1.3的安裝器會(huì)大量編譯生成BPL和DCU實(shí)時(shí)防護(hù)掃描會(huì)拖慢速度極端情況下還會(huì)誤刪未注冊(cè)的臨時(shí)文件。第三右鍵選擇“以管理員身份運(yùn)行”。安裝包本身建議從官網(wǎng)下載完整的離線安裝包體積通常在幾百M(fèi)B包含了所有子產(chǎn)品。如果你只需要其中的ExpressQuantumGrid和ExpressSkins安裝時(shí)選擇自定義組件即可不必全部安裝。我自己的經(jīng)驗(yàn)是先裝全家桶裝完再根據(jù)發(fā)布需求裁剪因?yàn)楹竺鎿Q膚、打印、報(bào)表說(shuō)不定哪一天就用上了省得返工。2.2 安裝器自動(dòng)編譯與IDE注冊(cè)安裝器跑起來(lái)后會(huì)先解壓組件源碼到默認(rèn)目錄通常是C:\Program Files\DevExpress 14.1\VCL然后自動(dòng)檢測(cè)所有已安裝的Delphi版本并為每個(gè)版本編譯對(duì)應(yīng)的DCU、BPL再注冊(cè)到IDE里。整個(gè)安裝過(guò)程最長(zhǎng)的是編譯環(huán)節(jié)十幾分鐘到半小時(shí)都正常期間不要切出去亂點(diǎn)。安裝完成后首次打開(kāi)Delphi組件面板會(huì)多出ExpressQuantumGrid、ExpressBars、ExpressSkins、ExpressEditors等頁(yè)簽。如果打開(kāi)IDE后組件面板沒(méi)有變化先別急著重裝檢查IDE的Component Install Packages列表里是否出現(xiàn)了DevExpress相關(guān)的設(shè)計(jì)期包。如果包已經(jīng)列出但控件沒(méi)顯示常見(jiàn)的坑是IDE緩存把%APPDATA%\Embarcadero\BDS\7.0\Closed Tools\或?qū)?yīng)版本目錄下的臨時(shí)文件清掉再重啟。安裝器在D7上的表現(xiàn)通常不如在新版XE系列上順滑因?yàn)镈7的注冊(cè)表項(xiàng)和路徑規(guī)則比較古老安裝器偶爾會(huì)漏寫Library路徑。這時(shí)不用慌用手工編譯的方式補(bǔ)上就行這正是老Delphi工程師的基本功。2.3 手工編譯的兜底方案安裝器失敗或者內(nèi)網(wǎng)環(huán)境無(wú)法用安裝器的場(chǎng)景我遇到過(guò)不止一次。兜底方案是手動(dòng)打開(kāi)包文件編譯路徑在C:\Program Files\DevExpress 14.1\VCL\Sources\下每個(gè)子產(chǎn)品都有一個(gè)或多個(gè).dpk文件。打開(kāi)一個(gè)工程組.dpg后逐個(gè)右鍵選擇Compile和Install。對(duì)于D7建議先編譯運(yùn)行時(shí)包再編譯設(shè)計(jì)期包。運(yùn)行時(shí)包的名字一般是cxLibrary.dpk、cxGrid.dpk、dxSkins.dpk這類設(shè)計(jì)期包以dcl開(kāi)頭比如dclcxLibrary.dpk、dclcxGrid.dpk。編譯順序很重要先底層庫(kù)后高層控件否則會(huì)出現(xiàn)找不到cxClasses.dcu的錯(cuò)誤。手工編譯時(shí)還要確認(rèn)輸出目錄。在D7的Project Options Directories/Conditionals里把Package output directory指向一個(gè)統(tǒng)一的Bin目錄比如C:\DevExpress14\Bin然后把該目錄同時(shí)加入系統(tǒng)PATH。設(shè)計(jì)期包注冊(cè)成功后Delphi會(huì)提示“Package installed successfully”組件面板隨即刷新這一步走通后面就順暢多了。3. 工程集成與運(yùn)行時(shí)配置3.1 搜索路徑與DCU管理組件裝好只是第一步真正讓工程能編譯還得把DCU和源文件路徑配好。在D7中打開(kāi)Tools Environment Options Library Library Path把DevExpress的Sources目錄加進(jìn)去。注意這里加的是Sources根目錄因?yàn)榻M件內(nèi)部有大量uses引用DevExpress把公共單元都放在Sources層按子目錄組織IDE在編譯時(shí)能自動(dòng)遞歸查找。我習(xí)慣把路徑按明確順序排列先寫Sources根目錄再寫Lib目錄避免多個(gè)版本源文件互相干擾。DCU的管理是另一個(gè)容易翻車的點(diǎn)。DevExpress 14.1.3安裝器會(huì)為每個(gè)IDE版本生成對(duì)應(yīng)的Lib\D7、Lib\DXE7這類目錄編譯輸出默認(rèn)也指向?qū)?yīng)分支。如果你手工編譯過(guò)一定要保證IDE搜索路徑里的DCU和當(dāng)前編譯器版本一致千萬(wàn)別手滑把D7的DCU目錄放在了XE7工程前面否則一連串“Unit cxGrid was compiled with a different version of cxClasses”會(huì)徹底打斷你的節(jié)奏。強(qiáng)烈建議在每個(gè)IDE的Library Path里只保留當(dāng)前版本的輸出目錄并且把其他版本目錄從路徑中刪除。3.2 運(yùn)行時(shí)包的分發(fā)策略開(kāi)發(fā)期用設(shè)計(jì)期包發(fā)布時(shí)則要決定用運(yùn)行時(shí)包還是靜態(tài)鏈接。運(yùn)行時(shí)包模式下exe體積小但客戶機(jī)器上必須安裝對(duì)應(yīng)的BPL和DLLDevExpress 14.1.3的運(yùn)行時(shí)包依賴關(guān)系比較復(fù)雜比如cxGrid依賴cxLibrarycxLibrary又依賴dxTheme。我踩過(guò)的坑是只拷貝了cxGrid的BPL結(jié)果客戶機(jī)器上一運(yùn)行就報(bào)“無(wú)法找到cxLibrary.bpl”。解決方法是寫一個(gè)小工具遍歷工程引用的BPL名稱然后把DevExpress Bin目錄下所有同名BPL一次性復(fù)制到程序目錄或系統(tǒng)目錄。如果不想管BPL也可以選擇靜態(tài)鏈接。在Project Options Packages中取消勾選“Build with runtime packages”編譯后所有控件代碼打進(jìn)exe體積增加十幾MB但部署簡(jiǎn)單U盤拷走就能跑。對(duì)于老舊的D7項(xiàng)目我的經(jīng)驗(yàn)是盡量用靜態(tài)鏈接因?yàn)镈7程序在客戶那邊的運(yùn)行環(huán)境五花八門少一個(gè)外部依賴就少一個(gè)故障點(diǎn)。4. 客戶端事件與常用開(kāi)發(fā)場(chǎng)景4.1 客戶端事件模型的理解搜索“DevExpress clientside event”經(jīng)常能看到這個(gè)詞但在VCL體系里它并不是Web開(kāi)發(fā)中那種瀏覽器端事件而是指控件在應(yīng)用客戶端進(jìn)程內(nèi)觸發(fā)的事件處理機(jī)制。換句話說(shuō)所有界面交互響應(yīng)都在用戶桌面端的程序里直接完成不需要請(qǐng)求服務(wù)器也不涉及網(wǎng)絡(luò)往返。對(duì)習(xí)慣了Web開(kāi)發(fā)的人來(lái)說(shuō)這個(gè)概念要注意區(qū)分別在Delphi里找什么“客戶端腳本”那是不存在的。真正重點(diǎn)掌握的是DevExpress控件的事件分類。以cxGrid為例最常用的是OnCellClick、OnCellDblClick、OnCustomDrawCell、OnCustomDrawColumnHeader以及Styles.OnGetContentStyle。這些事件的運(yùn)行機(jī)制和標(biāo)準(zhǔn)VCL事件類似但提供了更細(xì)粒度的機(jī)會(huì)比如在OnCustomDrawCell里你可以拿到ACanvas、AViewInfo直接畫底色、畫圖標(biāo)實(shí)現(xiàn)“條件高亮”這類在標(biāo)準(zhǔn)TDBGrid里要寫一堆代碼的效果。4.2 cxGrid實(shí)現(xiàn)條件高亮示例下面這段代碼是我項(xiàng)目里用了很久的條件高亮處理它會(huì)在數(shù)量小于安全庫(kù)存時(shí)把對(duì)應(yīng)行的單元格背景刷成淺紅色procedure TForm1.cxGrid1DBTableView1StylesGetContentStyle( Sender: TcxCustomGridTableView; ARecord: TcxCustomGridRecord; AItem: TcxCustomGridTableItem; out AStyle: TcxStyle); begin AStyle : nil; if ARecord nil then Exit; if AItem cxGrid1DBTableView1Qty then if ARecord.Values[cxGrid1DBTableView1Qty.Index] 10 then AStyle : cxStyleRed; // 在cxStyleRepository中預(yù)定義 end;這里的ARecord.Values[索引]是直接取單元格值無(wú)需訪問(wèn)數(shù)據(jù)集效率比通過(guò)DataSet字段反查高得多。cxStyleRed可以預(yù)先放在cxStyleRepository里設(shè)好顏色和字體運(yùn)行后整行的內(nèi)容樣式都能統(tǒng)一應(yīng)用。這就是DevExpress相對(duì)標(biāo)準(zhǔn)控件的核心優(yōu)勢(shì)數(shù)據(jù)和表現(xiàn)分離事件鉤子多定制能力強(qiáng)。4.3 與老數(shù)據(jù)庫(kù)工程聯(lián)動(dòng)老工程最典型的形態(tài)是ADO連接SQLServer或Access窗體上放一個(gè)TADOTable加TDataSource再掛cxGrid。這個(gè)組合下DevExpress的DB-Aware模式依然好用把View的DataController.DataSource指向DataSource即可。一個(gè)容易忽略的點(diǎn)是當(dāng)TADOTable在D7下使用AnsiString時(shí)中文顯示容易亂碼而DevExpress已經(jīng)做了內(nèi)部Unicode轉(zhuǎn)換所以界面顯示反而比原生DBGrid更穩(wěn)定。數(shù)據(jù)刷新時(shí)建議使用cxGrid1DBTableView1.DataController.DataSource.DataSet.Refresh或者用DataController.Refresh不要直接調(diào)用GridView.Refresh后者在某些版本下會(huì)觸發(fā)設(shè)計(jì)期繪制異常。這個(gè)區(qū)別我是在一次現(xiàn)場(chǎng)演示時(shí)踩出來(lái)的客戶數(shù)據(jù)量大直接刷新界面閃白換成DataController刷之后就絲滑了。5. 踩坑實(shí)錄與問(wèn)題排查5.1 安裝期問(wèn)題速查我把這些年遇到的高頻問(wèn)題整理成一張速查表方便大家直接對(duì)照?qǐng)?bào)錯(cuò)或現(xiàn)象根本原因解決方案安裝器檢測(cè)不到Delphi 7注冊(cè)表IDE路徑損壞或安裝器權(quán)限不足手動(dòng)打開(kāi).dpk編譯或用管理員身份安裝組件面板無(wú)DevExpress頁(yè)簽設(shè)計(jì)期包未注冊(cè)或IDE緩存異常檢查Install Packages列表清理IDE緩存打開(kāi)窗體報(bào)“Class TCxGrid not found”發(fā)布機(jī)或同事機(jī)器缺少設(shè)計(jì)期包重新安裝組件確保dcl開(kāi)頭的包已注冊(cè)編譯報(bào)“無(wú)法找到cxClasses.dcu”Library Path未配置或配錯(cuò)版本目錄添加Sources根目錄核對(duì)IDE版本安裝期的問(wèn)題大多數(shù)不是安裝包損壞而是路徑和權(quán)限。曾經(jīng)有一臺(tái)64位Windows Server上的D7安裝器一直無(wú)法把BPL寫到系統(tǒng)目錄后來(lái)發(fā)現(xiàn)是UAC把重定向到了虛擬存儲(chǔ)。解決辦法是把DevExpress Bin目錄單獨(dú)建在D盤并且給D7的快捷方式設(shè)置“以管理員身份運(yùn)行”。5.2 編譯期問(wèn)題排查編譯期最讓人頭疼的是“Unit was compiled with a different version of”這類錯(cuò)誤。這個(gè)錯(cuò)誤的本質(zhì)是工程里混用了不同版本編譯出的DCU比如引用路徑中D7和XE7的DCU目錄同時(shí)存在或者舊的DCU沒(méi)有清理干凈。排查步驟可以按順序來(lái)先看Library Path里是否有多個(gè)DevExpress目錄再看工程文件里是否有絕對(duì)路徑指向舊的Lib目錄最后把整個(gè)工程里所有.dcu臨時(shí)文件刪掉重新編譯一次90%的問(wèn)題能在這個(gè)環(huán)節(jié)解決。還有個(gè)隱蔽問(wèn)題是在D7里用到了XPStyleManifest或者WinXP主題相關(guān)單元時(shí)如果順序不對(duì)會(huì)報(bào)F2048錯(cuò)誤。DevExpress的控件在主題支持上依賴uxtheme.dllD7下需要把Themes單元放在uses列表的最前面。老程序員通常寫成uses Windows, Messages, ...沒(méi)注意順序編譯就掛了。調(diào)整之后問(wèn)題立消這個(gè)細(xì)節(jié)寫進(jìn)很多項(xiàng)目的注釋里新手往往不知道。5.3 運(yùn)行期問(wèn)題記錄運(yùn)行期最經(jīng)典的問(wèn)題有兩個(gè)。第一個(gè)是換膚后程序界面所有字體變小這是因?yàn)镋xpressSkins的默認(rèn)字體設(shè)置跟老工程不一致。解決方法是在程序啟動(dòng)時(shí)設(shè)置dxSkinsUserSkinPath并顯式指定GetCurrentSkin同時(shí)覆蓋每個(gè)窗體的Font.Name和Font.Size。第二個(gè)問(wèn)題是網(wǎng)格在滾動(dòng)時(shí)閃爍老顯卡機(jī)器上特別明顯可以在cxGrid1DBTableView1.OptionsView里開(kāi)啟OptimizedDraw性能提升立竿見(jiàn)影。另外提醒一句D7工程的字符串處理一定要謹(jǐn)慎。如果你在D7和XE7之間共享代碼event handler里用String(0)或直接操作PChar的地方都要標(biāo)注出來(lái)DevExpress 14.1.3完美兼容兩套字符串體系但這些邊界處理如果沒(méi)有做好在XE7下運(yùn)行時(shí)會(huì)悄悄產(chǎn)生亂碼等到客戶發(fā)現(xiàn)再來(lái)排查往往已經(jīng)過(guò)去很久。根據(jù)我個(gè)人經(jīng)驗(yàn)把這套14.1.3用順之后最值得投資的時(shí)間是仔細(xì)讀一遍cxGrid的事件說(shuō)明。它值得不是安裝時(shí)看而是真正做業(yè)務(wù)時(shí)逐個(gè)驗(yàn)證明白了事件觸發(fā)順序和DataController的關(guān)系后面處理大數(shù)據(jù)量、排序、篩選、分組這些需求都會(huì)從容很多。最后再分享一個(gè)小技巧編譯發(fā)布版之前記得在Project Options Compiler里把Optimization打開(kāi)老版本控件配合優(yōu)化開(kāi)關(guān)在某些數(shù)據(jù)密集型界面上能有20%左右的性能提升這個(gè)收益幾乎白撿。本文還有配套的精品資源點(diǎn)擊獲取