目救星:KonopkaControls控件包安裝與實(shí)戰(zhàn)避坑指南)
簡(jiǎn)介面向Delphi 13.1開(kāi)發(fā)者的KonopkaControls 8.0.1控件包是擴(kuò)展VCL標(biāo)準(zhǔn)組件庫(kù)的第三方界面控件集合能有效補(bǔ)充原生控件在界面表現(xiàn)與交互能力上的不足適合桌面應(yīng)用開(kāi)發(fā)及快速原型構(gòu)建。壓縮包共2000個(gè)文件包含1128個(gè)PNG圖片資源、263個(gè)HPP頭文件和259個(gè)DCU編譯單元另有DFM窗體、PAS源碼、BPL運(yùn)行包、CHM幫助文檔、DPK描述文件及部署腳本等全部?jī)?nèi)容按源碼、庫(kù)目錄、幫助、示例與部署工具分類存放便于按需檢索和二次開(kāi)發(fā)。該控件包包體僅為25.41MB已有89人學(xué)習(xí)與下載使用。資源附完整源代碼、編譯好的運(yùn)行庫(kù)、KSVC變更記錄與Demo工程既能直接集成到既有項(xiàng)目也可通過(guò)閱讀PAS和DFM文件弄清控件實(shí)現(xiàn)機(jī)制。對(duì)于希望提升Delphi界面開(kāi)發(fā)效率或研究VCL控件封裝方式的開(kāi)發(fā)者該資源具備明確參考價(jià)值尤其適合有Object Pascal基礎(chǔ)的入門(mén)與進(jìn)階者。1. 為什么我還在裝 KonopkaControls一個(gè) For13.0 的控件包憑什么讓老 Delphi 項(xiàng)目續(xù)命學(xué)習(xí) Delphi 的人通常第一課是擺一個(gè) Button但真正接手一個(gè)跑了十多年的老工程時(shí)你才會(huì)發(fā)現(xiàn)界面上的按鈕、標(biāo)簽頁(yè)、狀態(tài)欄早就不全是原生 VCL而是靠第三方控件撐著。KonopkaControls簡(jiǎn)稱 KNC就是這類控件里最常見(jiàn)的面孔之一一套包含按鈕、Panel、Tab、樹(shù)、列表、狀態(tài)欄等幾十個(gè)控件的源碼包體積不大卻能把舊項(xiàng)目的 UI 骨架穩(wěn)穩(wěn)保住。標(biāo)題里 For13.0 的 13指的不是 Delphi 的營(yíng)銷版本號(hào)而是 DCC 編譯器版本號(hào)對(duì)應(yīng)的是 Delphi 7 時(shí)代的產(chǎn)品線而 8.0.1 是 KNC 的發(fā)行版本370 是構(gòu)建序號(hào)。這篇我就按實(shí)際安裝順序把解壓、編譯、注冊(cè)進(jìn) IDE、在數(shù)據(jù)庫(kù) TreeView 和 Panel 圓角場(chǎng)景里跑起來(lái)以及最容易翻車(chē)的幾個(gè)點(diǎn)一次講完。適合正在接手舊工程、又不想被控件初始化問(wèn)題卡住的人。2. 先拆包KNC 到底是一套什么控件8.0.1 又代表什么拿到KonopkaControls-370-8.0.1-For13.0.zip第一件事不是急著解壓而是先弄明白壓縮包里裝的是什么、版本號(hào)怎么讀。KNC 是一個(gè)純粹的 VCL 控件集主要服務(wù)于 Win32 傳統(tǒng)界面開(kāi)發(fā)不做跨平臺(tái)不做現(xiàn)代扁平化皮膚但它有一個(gè)特殊價(jià)值源碼完全開(kāi)放編譯產(chǎn)物只有 .bpl/.dcp沒(méi)有任何第三方圖形庫(kù)依賴。2.1 為什么遺留工程離不開(kāi)這套控件KNC 的歷史可以追溯到 Delphi 5/6/7 時(shí)代很多企業(yè)級(jí)系統(tǒng)選它不是因?yàn)楹每炊且驗(yàn)榉€(wěn)定。它提供的控件覆蓋了傳統(tǒng)業(yè)務(wù)系統(tǒng)最常見(jiàn)的交互帶狀態(tài)的按鈕、可自繪的面板、多頁(yè)簽切換、樹(shù)形菜單、狀態(tài)欄、列表視圖、日期選擇等。這些控件在標(biāo)準(zhǔn) VCL 里都能找到同類但 KNC 做了一層封裝讓“統(tǒng)一風(fēng)格”這件事變得容易。另一個(gè)現(xiàn)實(shí)原因是被迫繼承。很多舊項(xiàng)目在創(chuàng)建時(shí)就用 KNC 替代了部分原生控件窗體上遍布TKnCButton、TKnCPanel之類的組件類型。你接手后如果不裝這套控件IDE 連窗體都打不開(kāi)會(huì)直接報(bào)“無(wú)法解析類名”。所以不管它好不好看先把編譯環(huán)境復(fù)原是接手此類項(xiàng)目的第一優(yōu)先級(jí)。如果你是新項(xiàng)目選型我的建議是謹(jǐn)慎一點(diǎn)KNC 適合做傳統(tǒng)管理軟件界面但如果你要的是圓角大卡片、動(dòng)畫(huà)過(guò)渡、深色主題那它顯然不是最佳選擇。2.2 版本號(hào)里的三重信息370、8.0.1、For13.0壓縮包文件名里藏著三組信息分別對(duì)應(yīng)構(gòu)建、發(fā)行和 IDE 兼容標(biāo)記。把它們讀懂你在裝錯(cuò)版本時(shí)就能更快反應(yīng)過(guò)來(lái)。字段含義影響370構(gòu)建序號(hào)表示這是第 370 次構(gòu)建實(shí)際使用中幾乎不用關(guān)注8.0.1發(fā)行版本號(hào)決定源碼 API 是否變化不要跨大版本混用For13.0DCC 編譯器版本標(biāo)記決定能裝進(jìn)哪一個(gè) Delphi IDE這部分最關(guān)鍵這里的 For13.0 最容易誤解。Borland 的編譯器版本號(hào)和產(chǎn)品名并不是同一套數(shù)字Delphi 7 的 DCC 編譯器版本就是 13.0所以 For13.0 實(shí)際是說(shuō)“這套源碼對(duì)應(yīng) Delphi 7 的工具鏈”。而標(biāo)題里寫(xiě)的 Delphi 13.1更像下載站點(diǎn)自己的分類叫法不是 Embarcadero 的官方命名。你安裝時(shí)唯一要確認(rèn)的就是本機(jī)編譯器的版本字符串與控件包要求一致否則編譯期會(huì)報(bào)版本不匹配常見(jiàn)提示是Invalid compiler version或者Package ... was compiled with a different version of Delphi。2.3 解壓后你該看到的目錄結(jié)構(gòu)解壓這類源碼包時(shí)我會(huì)先看頂層目錄里有沒(méi)有Source、Docs、Demo、Bin這四個(gè)目錄。KNC 的正常分發(fā)形態(tài)基本遵循這套規(guī)矩具體名稱可能有差異但邏輯一致。目錄作用是否必須Source/Runtime運(yùn)行期控件源碼編譯 .bpl 用必須Source/Design設(shè)計(jì)期注冊(cè)與屬性編輯器源碼必須Docs幫助文檔、版本變更記錄可選Demo示例工程看你實(shí)際需要可選Bin預(yù)編譯的 .bpl/.dcp可選建議自己編譯不要直接拿別人的 Bin 目錄里的 .bpl 往 IDE 里塞。原因很簡(jiǎn)單那些預(yù)編譯包可能是 Debug 版或者編譯選項(xiàng)和你機(jī)器不一致輕則 IDE 提示缺少rtl70.bpl重則設(shè)計(jì)期直接崩掉。自己從源碼編譯一次整個(gè)過(guò)程也就幾分鐘后續(xù)排查問(wèn)題還能直接進(jìn)源碼這是最穩(wěn)妥的路線。3. 把 KonopkaControls 裝進(jìn) Delphi IDEdpk 編譯與設(shè)計(jì)期注冊(cè)安裝 KNC 的核心不是解壓也不是復(fù)制文件而是把 .dpkDelphi Package 工程編譯成運(yùn)行期包和設(shè)計(jì)期包再讓 IDE 在設(shè)計(jì)期加載。理解這兩個(gè)概念后面所有坑都好解決。3.1 安裝前的環(huán)境準(zhǔn)備路徑、庫(kù)目錄、包名解壓路徑最好不要放在帶有空格或者中文的深層目錄里某些老編譯器對(duì)路徑處理沒(méi)有現(xiàn)代 IDE 那么寬容。我一般習(xí)慣壓在D:\Components\KonopkaControls-8.0.1這類結(jié)構(gòu)下。接下來(lái)要做的第一件事是把源碼目錄加進(jìn) Delphi 的庫(kù)搜索路徑否則編譯時(shí)找不到KncConst.pas這類公共單元。以 Delphi 7 為例打開(kāi)Tools - Environment Options - Library - Library Path把D:\Components\KonopkaControls-8.0.1\Source\Runtime和D:\Components\KonopkaControls-8.0.1\Source\Design都加進(jìn)去。注意不要只加根目錄因?yàn)樵创a文件往往分散在子目錄里。如果你用的是 RAD Studio 10.3 之后的版本路徑入口在Tools - Options - Environment Options - Delphi Options - Library同樣追加 Source 目錄。一個(gè)容易被忽略的細(xì)節(jié)環(huán)境變量里的BDS指向當(dāng)前 IDE 的根目錄很多構(gòu)建腳本會(huì)依賴它。所以在命令行里安裝時(shí)建議先確認(rèn)這個(gè)變量存在避免后續(xù) dcc32 找不到基礎(chǔ)包。3.2 用命令行編譯運(yùn)行期包和設(shè)計(jì)期包命令行編譯的好處是可控、可重復(fù)比在 IDE 里點(diǎn)點(diǎn)點(diǎn)更容易定位問(wèn)題。先打開(kāi)一個(gè) CMD 窗口逐行執(zhí)行下面的命令。set KNC_HOMED:\Components\KonopkaControls-8.0.1 set DELPHI_BINC:\Program Files\Borland\Delphi7\Bin cd /d %KNC_HOME%\Source\Runtime %DELPHI_BIN%\dcc32.exe -B -Q KNC_R.dpk if errorlevel 1 goto :err cd /d %KNC_HOME%\Source\Design %DELPHI_BIN%\dcc32.exe -B -Q dclKNC.dpk if errorlevel 1 goto :err echo OK goto :end :err echo Build Failed :end這段腳本先編譯運(yùn)行期包KNC_R.dpk再編譯設(shè)計(jì)期包dclKNC.dpk。-B 表示強(qiáng)制全部重建避免增量編譯緩存帶來(lái)莫名其妙的問(wèn)題-Q 是安靜模式只輸出錯(cuò)誤和警告if errorlevel 1判斷上一條命令是否失敗。文件名的具體寫(xiě)法以壓縮包里的 .dpk 為準(zhǔn)如果運(yùn)行期包叫KNC_Runtime.dpk就把KNC_R.dpk換掉。這里要特別說(shuō)明為什么必須先編譯運(yùn)行期包。設(shè)計(jì)期包內(nèi)部會(huì)requires運(yùn)行期包比如聲明requires KNC_R;如果你還沒(méi)有編譯出運(yùn)行期包對(duì)應(yīng)的 .dcp/.bpl設(shè)計(jì)期包編譯時(shí)就會(huì)報(bào)“找不到 KNC_R”。這也是為什么我不建議在一個(gè) dcc32 命令里同時(shí)編譯兩個(gè)包去碰運(yùn)氣分開(kāi)編譯能更早暴露缺口。新版 RAD Studio 里 .dpk 已經(jīng)退居次要IDE 默認(rèn)生成 .dproj 工程。安裝時(shí)用 msbuild 更合適msbuild dclKNC.dproj /p:ConfigRelease /p:PlatformWin32ConfigRelease保證生成的是 Release 版運(yùn)行期包避免把調(diào)試符號(hào)帶進(jìn)最終發(fā)布PlatformWin32是因?yàn)檫@類 VCL 源碼大多還沒(méi)遷移到 Win64如果你在 64 位設(shè)計(jì)期環(huán)境里安裝出錯(cuò)優(yōu)先把 IDE 的 Target Platform 切到 Win32 再測(cè)試。3.3 設(shè)計(jì)期包安裝后的驗(yàn)證方法編譯完成后打開(kāi) Delphi IDE進(jìn)入Component - Install Packages點(diǎn)Add選擇剛才生成的dclKNC.bpl。如果此時(shí) IDE 提示“Package already exists”說(shuō)明以前裝過(guò)需要先移除舊版本不要強(qiáng)行覆蓋。安裝成功后打開(kāi)工具面板找到新增的組件頁(yè)頁(yè)面名稱通常是KNC或者Konopka。最簡(jiǎn)單的驗(yàn)證方式是新建一個(gè) Application往窗體上拖一個(gè) KNC 按鈕和一個(gè) KNC 狀態(tài)欄確認(rèn)屬性編輯器和對(duì)象管理器都能正常顯示。如果拖組件時(shí) IDE 崩潰直接進(jìn)第 5 章排查最常見(jiàn)原因是運(yùn)行期包沒(méi)先編譯、或者運(yùn)行期包路徑?jīng)]加入環(huán)境變量。4. 在真實(shí)項(xiàng)目里用 KNC組件選型、數(shù)據(jù)庫(kù) TreeView 與界面細(xì)節(jié)裝完包只是開(kāi)始真正讓人頭疼的是“怎么用”。這一章我按現(xiàn)實(shí)業(yè)務(wù)場(chǎng)景來(lái)聊先挑出值得優(yōu)先認(rèn)識(shí)的幾個(gè)控件再講數(shù)據(jù)庫(kù)驅(qū)動(dòng) TreeView 的填充套路最后處理 Panel 圓角和子控件間距這兩個(gè)搜索頻率極高的小需求。4.1 值得優(yōu)先使用的幾個(gè) KNC 控件KNC 的控件數(shù)量不少但真正高頻率使用的是下面這幾個(gè)控件用途替代原生控件KNCButton帶自繪狀態(tài)的按鈕TButton/TSpeedButtonKNCPanel可自繪面板容器TPanelKNCTabBar多頁(yè)簽切換TTabControlKNCStatusBar狀態(tài)欄信息展示TStatusBarKNCList列表視圖TListViewKNCTree樹(shù)形結(jié)構(gòu)TTreeView我通常會(huì)把 KNCButton 用于工具欄和功能按鈕因?yàn)樗С肿岳L按下?tīng)顟B(tài)界面看起來(lái)更像桌面客戶端。但要注意它不負(fù)責(zé)解決瀏覽器類問(wèn)題KNC 里沒(méi)有 WebBrowser 控件HTML 展示依然要用標(biāo)準(zhǔn) TWebBrowser這是很多新人的預(yù)期偏差先講清楚免得后面找控件找到懷疑人生。4.2 讓 KNC 的樹(shù)控件通過(guò)數(shù)據(jù)庫(kù)驅(qū)動(dòng)字段映射與刷新業(yè)務(wù)系統(tǒng)里最常見(jiàn)的樹(shù)是“部門(mén)樹(shù)”和“菜單樹(shù)”數(shù)據(jù)在數(shù)據(jù)庫(kù)里就是一張帶有 PID 的表。給 KNC 樹(shù)控件填數(shù)據(jù)時(shí)不需要關(guān)注控件內(nèi)部實(shí)現(xiàn)只用遞歸在內(nèi)存里搭節(jié)點(diǎn)樹(shù)再賦值給控件即可。下面是標(biāo)準(zhǔn)寫(xiě)法procedure LoadTreeFromDataset( ATree: TTreeView; ADataSet: TDataSet; AIdField, AParentField, ANameField: string); var NodeList: TStringList; I: Integer; Node: TTreeNode; ParentNode: TTreeNode; ParentId: string; begin ATree.Items.BeginUpdate; try ATree.Items.Clear; NodeList : TStringList.Create; try ADataSet.First; while not ADataSet.Eof do begin Node : ATree.Items.Add(nil, ADataSet.FieldByName(ANameField).AsString); Node.Data : Pointer(ADataSet.FieldByName(AIdField).AsInteger); NodeList.AddObject(ADataSet.FieldByName(AIdField).AsString, Node); ADataSet.Next; end; ADataSet.First; while not ADataSet.Eof do begin ParentId : ADataSet.FieldByName(AParentField).AsString; if ParentId then begin I : NodeList.IndexOf(AParentField ParentId); if I 0 then begin ParentNode : TTreeNode(NodeList.Objects[I]); ATree.Items.AddChild(ParentNode, ADataSet.FieldByName(ANameField).AsString) .Data : Pointer(ADataSet.FieldByName(AIdField).AsInteger); end; end; ADataSet.Next; end; finally NodeList.Free; end; finally ATree.Items.EndUpdate; end; end;這段代碼的邏輯分兩遍第一遍先按數(shù)據(jù)庫(kù)順序把每條記錄都生成根節(jié)點(diǎn)并把 ID 存到Node.Data第二遍再根據(jù) PID 把記錄移動(dòng)到對(duì)應(yīng)父節(jié)點(diǎn)下。用兩個(gè)循環(huán)是為了避免出現(xiàn)父節(jié)點(diǎn)還沒(méi)創(chuàng)建時(shí)子節(jié)點(diǎn)無(wú)處掛靠的問(wèn)題。BeginUpdate/EndUpdate防止刷新過(guò)程中界面閃爍NodeList用字符串做索引是因?yàn)樵跀?shù)據(jù)量不大時(shí)字符串查找比遍歷 TTreeNode 更直觀。實(shí)際使用時(shí)如果表里 ID 是整數(shù)序列建議把AIdField和AParentField做成Integer參數(shù)速度會(huì)更好。4.3 Panel 圓角、子控件間距與自繪常見(jiàn)參數(shù)“Panel 控件圓角”和“子控件間距”是 Delphi 開(kāi)發(fā)者經(jīng)常搜的兩類問(wèn)題。KNC 面板自身不一定提供圓角屬性但你可以借助 Win32 區(qū)域設(shè)置做統(tǒng)一處理。圓角本質(zhì)上是把窗口客戶區(qū)域切成圓角矩形Windows 自帶的CreateRoundRectRgn就能實(shí)現(xiàn)。procedure MakeRoundedPanel(APanel: TPanel; ARadius: Integer); var HRgn: HRGN; begin HRgn : CreateRoundRectRgn( 0, 0, APanel.Width, APanel.Height, ARadius, ARadius); SetWindowRgn(APanel.Handle, HRgn, True); DeleteObject(HRgn); end;CreateRoundRectRgn的四個(gè)前參數(shù)是區(qū)域左上角和右下角坐標(biāo)后兩個(gè)參數(shù)分別是橢圓寬高也就是圓角半徑。半徑設(shè)成12適合一般管理界面設(shè)成24就是明顯的大圓角。需要注意的是SetWindowRgn接管后窗口系統(tǒng)不再對(duì)區(qū)域外做命中測(cè)試所以不要把半徑設(shè)到面板寬度的三分之一以上否則觸碰到圓角邊緣時(shí)按鈕會(huì)“點(diǎn)不中”。子控件間距更推薦用 VCL 自帶的對(duì)齊體系解決而不是手動(dòng)設(shè)置Left/Top。做法是給容器內(nèi)每個(gè)子控件設(shè)Align alTop或alLeft再通過(guò)Margins屬性控制外間距。KNC 控件繼承自標(biāo)準(zhǔn) VCL 控件所以Margins.Left/Right/Top/Bottom這幾個(gè)參數(shù)都有效。這樣窗口調(diào)整大小時(shí)間距會(huì)自動(dòng)縮放不會(huì)出現(xiàn)控件疊在一起的翻車(chē)現(xiàn)場(chǎng)。5. 避坑清單安裝、運(yùn)行與升級(jí)最容易翻車(chē)的 5 個(gè)地方這一章全是血淚經(jīng)驗(yàn)。KNC 這類老牌第三方控件包坑點(diǎn)不在功能而在環(huán)境適配。下面每一條都按“現(xiàn)象 - 原因 - 解決”來(lái)寫(xiě)。5.1 現(xiàn)象設(shè)計(jì)期包明明安裝了IDE 里卻還提示需要安裝有時(shí)候你點(diǎn)完 Install PackagesIDE 也顯示加載成功但新建窗體拖 KNC 組件時(shí)還是提示類不存在。原因多是 IDE 緩存了舊的設(shè)計(jì)期包索引或者安裝的是 64 位設(shè)計(jì)期包而工程運(yùn)行平臺(tái)是 Win32。解決方法是先用Component - Install Packages把舊包移除關(guān)閉 IDE刪除用戶目錄下的*.bpl緩存的.drc/.dcu文件再重新打開(kāi) IDE 安裝。如果還不夠檢查T(mén)ools - Options里的 Delphi 庫(kù)路徑是否包含 Source 目錄缺少的話編譯器能編譯但設(shè)計(jì)期找不到類型聲明。5.2 現(xiàn)象編譯按鈕時(shí)報(bào) File not found: KncConst.pas這是源碼包安裝中最常見(jiàn)的報(bào)錯(cuò)。KncConst.pas是 KNC 的公共常量單元它不在某個(gè)具體控件目錄里而是放在 Source 根目錄或者公共目錄中。報(bào)錯(cuò)原因基本是庫(kù)搜索路徑只加了阻塞的單個(gè)子目錄編譯器在其他單元里uses KncConst時(shí)根本找不到文件。解決方法是把整個(gè) KNC 的 Source 目錄樹(shù)全部加進(jìn) Library Path而不是只加其中一個(gè)文件夾。解壓時(shí)也盡量保持目錄結(jié)構(gòu)不變不要只復(fù)制部分文件。5.3 現(xiàn)象程序在 IDE 里正常跑雙擊 exe 卻閃退這種問(wèn)題在 IDE 里看不出來(lái)因?yàn)?IDE 會(huì)自動(dòng)加載運(yùn)行期包。但脫離 IDE 后exe 動(dòng)態(tài)鏈接到 KNC 的 .bpl如果目標(biāo)機(jī)器上沒(méi)有這些 .bpl程序啟動(dòng)時(shí)就會(huì)提示“無(wú)法找到 KNC_R.bpl”然后退出。解決方法是發(fā)布時(shí)把運(yùn)行期包一起帶上。常見(jiàn)做法是把.bpl文件放在 exe 同目錄或者用 Inno Setup 在[Files]段顯式復(fù)制到 System32。更穩(wěn)妥的方案是在工程里把Runtime Packages設(shè)為Build with runtime packages off這樣生成的 exe 把控件代碼直接鏈接進(jìn)主程序發(fā)布時(shí)只帶rtl70.bpl和vcl70.bpl目標(biāo)機(jī)器就算沒(méi)裝 Delphi 也能跑。5.4 現(xiàn)象KNC 控件搶焦點(diǎn)Tab 鍵順序亂跳KNC 里的自繪按鈕在獲得焦點(diǎn)時(shí)會(huì)通過(guò)消息機(jī)制改變繪制狀態(tài)。如果你在窗體里混用了原生 TButton 和 KNCButton可能會(huì)出現(xiàn)按 Tab 后焦點(diǎn)不進(jìn)入 KNC 控件、或者進(jìn)入后無(wú)法正常離開(kāi)的問(wèn)題。原因是設(shè)計(jì)期包的 Windows 消息處理與原生控件不同而 KNC 的WM_GETDLGCODE必須返回正確的標(biāo)志位否則對(duì)話框?qū)Ш竭壿嫊?huì)忽略它。解決方法是檢查該控件是否有TabStop屬性確認(rèn)設(shè)為 True同時(shí)在Form.OnShow里調(diào)用一次Control.SetFocus再移到別處強(qiáng)制刷新焦點(diǎn)鏈。如果還不行看看是不是把 KNCButton 放進(jìn)了另一個(gè)自繪容器容器需要設(shè)置ControlStyle里的csAcceptsControls。5.5 現(xiàn)象從 Delphi 7 遷移到新版 Delphi 后中文顯示亂碼KNC 的源碼寫(xiě)于 ANSI 時(shí)代字符串常量多是用String保存新版 Delphi 默認(rèn) UnicodeString 后字符集轉(zhuǎn)換會(huì)出現(xiàn)亂碼尤其表現(xiàn)在狀態(tài)欄和列表列頭上。原因不是控件壞了而是單元文件里沒(méi)有指定代碼頁(yè)編譯器按當(dāng)前系統(tǒng) ANSI 解析。解決方法有兩個(gè)方向一是到項(xiàng)目設(shè)置里把Default codepage設(shè)成 936讓 ANSI 字符串按 GBK 解釋二是把所有界面展示字符串改用 Tnt 控件或者直接改成WideString。如果你只是臨時(shí)遷移方法一最快如果想長(zhǎng)期維護(hù)建議用TEncoding.UTF8.GetString做一層讀取轉(zhuǎn)換而不是一個(gè)控件一個(gè)控件去改。6. 用源碼級(jí)技巧繼續(xù)壓榨 KNC自定義圓角、多線程刷新與調(diào)試黑匣子最后一章我不寫(xiě)安裝流程而是說(shuō)幾個(gè)能直接提升手感的小技巧。這些技巧不一定都在 KNC 官方文檔里但它們能幫你把黑匣子變成透明盒子。關(guān)于圓角前面那段MakeRoundedPanel已經(jīng)夠用但如果你不想每個(gè)窗體都復(fù)制一遍可以把這段代碼放進(jìn)一個(gè)公共單元然后在窗體OnShow里統(tǒng)一循環(huán)處理比如遍歷容器內(nèi)的所有 TPanel 并調(diào)用圓角函數(shù)。這樣做的好處是團(tuán)隊(duì)里其他人不需要理解 Win32 API一行公共函數(shù)就能解決所有面板圓角需求。參數(shù)上我會(huì)固定成ARadius 12避免不同窗體圓角大小不一致導(dǎo)致界面風(fēng)格分裂。關(guān)于多線程刷新KNC 控件和普通 VCL 控件一樣不能在工作線程里直接修改Caption或Text否則會(huì)出現(xiàn)隨機(jī)性閃退。我一般使用Synchronize配合消息隊(duì)列把數(shù)據(jù)庫(kù)查詢結(jié)果打包進(jìn)自定義消息再在窗口函數(shù)里統(tǒng)一刷新樹(shù)控件。你不需要引入額外的庫(kù)Delphi 自帶的Winapi.Windows.PostMessage就能做到。注意一點(diǎn)PostMessage的 WParam/LParam 只能傳整數(shù)傳字符串要把字符串地址提前分配好否則消息處理時(shí)地址已經(jīng)釋放查起來(lái)非常費(fèi)時(shí)間。最后說(shuō)一個(gè)調(diào)試習(xí)慣KNC 這類控件源碼里通常有{$IFDEF DEBUG}分支你可以在自己的工程里定義一個(gè)KNC_DEBUG條件編譯把控件關(guān)鍵方法的入口和出口打印到日志文件。遇到控件行為詭異時(shí)先看日志再斷點(diǎn)不要一上來(lái)就翻代碼。這個(gè)習(xí)慣幫我省掉過(guò)很多次無(wú)意義的單步調(diào)試尤其是 5.4 那種焦點(diǎn)問(wèn)題日志比斷點(diǎn)更能快速定位是哪一層控件吞了消息。希望這些經(jīng)驗(yàn)?zāi)軒偷侥闵僮呶耶?dāng)年走過(guò)的彎路。本文還有配套的精品資源點(diǎn)擊獲取