戰(zhàn)解析)
我在早期寫自動化腳本時第一次接觸到易語言大漠模塊制作教程里的“獲取顏色 GetColor”這個命令起因很簡單做一個界面狀態(tài)監(jiān)測小工具需要知道軟件窗口里某個按鈕是不是已經(jīng)從灰色變成了可點(diǎn)擊狀態(tài)。當(dāng)時最直接的辦法不是截圖再算像素而是讀取那個坐標(biāo)點(diǎn)的顏色值。后來我逐漸發(fā)現(xiàn)如果每寫一個新腳本都把大漠DLL的注冊、對象創(chuàng)建、返回值轉(zhuǎn)換這些流程搬一遍效率實(shí)在太低。于是就有了把整套基礎(chǔ)能力封裝成易語言模塊的想法。這篇文章就以 GetColor 為切入口完整梳理一下我從零封裝大漠模塊的過程、原理和踩坑記錄給正在研究這類圖色命令的朋友做個參考。1. 為什么要花功夫封裝模塊而不直接調(diào)用大漠1.1 寫腳本時最不缺的就是重復(fù)代碼先說我一開始的做法新建一個窗口程序在按鈕事件里直接創(chuàng)建大漠對象調(diào)用方法用完就扔。這在只有一兩個腳本的時候沒什么問題但腳本一多麻煩就來了。比如某天我發(fā)現(xiàn) A 腳本里對象創(chuàng)建完沒有釋放B 腳本里引用的 DLL 版本和 A 不一致C 腳本里同樣的取色邏輯卻因?yàn)榉祷刂蹈袷讲煌瑢?dǎo)致判斷出錯。找原因的時間比寫代碼還長。后來我意識到反復(fù)復(fù)制粘貼“創(chuàng)建對象、調(diào)用命令、處理返回結(jié)果”這段樣板代碼本質(zhì)上是在給自己補(bǔ)課。大漠命令這么多如果不做一層封裝項(xiàng)目里就會到處散落著底層調(diào)用代碼后續(xù)維護(hù)和升級都很難受。尤其是 GetColor 這類基礎(chǔ)命令幾乎每個圖色腳本都會用把它封裝好一勞永逸。1.2 封裝之后接口才像“人話”直接調(diào)用大漠命令寫出來大概是這樣的對象.文本方法 (GetColor, 100, 200)。雖然能跑但可讀性一般。封裝成易語言模塊之后外部腳本只需要調(diào)用一個名字清晰的中文子程序取顏色 (100, 200)內(nèi)部做了什么、返回什么格式全部屏蔽掉。這樣做有三個直接好處接口簡化上層腳本只面對“取顏色”“顏色相似”“初始化”這類清晰接口不用記底層方法名。錯誤處理統(tǒng)一對象沒初始化、坐標(biāo)超范圍、返回空串等異常情況在模塊內(nèi)部統(tǒng)一處理上層只需要判斷返回值。方便擴(kuò)展以后要加 FindColor、FindMultiColor 等高級命令只需在模塊里繼續(xù)加公開子程序舊代碼不受影響。我自己實(shí)踐下來的體會是封裝之后寫新腳本的速度會明顯變快因?yàn)榛A(chǔ)能力已經(jīng)變成一塊現(xiàn)成的積木。1.3 為什么從 GetColor 入手大漠模塊里命令非常多有找圖、找色、識字、模擬鍵鼠、窗口操作等等但 GetColor 屬于最底層的那一批。很多高級命令比如 FindColor、找色區(qū)域判斷底層邏輯都離不開“取某個點(diǎn)的顏色然后做比較”。把這個命令的原理、返回格式、坐標(biāo)細(xì)節(jié)徹底搞清楚后面再學(xué)其他命令會順暢很多。另外 GetColor 命令本身邏輯足夠簡單非常適合作為造模塊的入門練習(xí)。先用它把“初始化、調(diào)用、返回處理”這一整條鏈路跑通之后再往模塊里添加復(fù)雜功能就是復(fù)制粘貼加改參數(shù)的事了。2. GetColor 到底取回了什么顏色串、坐標(biāo)與DPI的底層邏輯2.1 屏幕上一個個像素點(diǎn)背后是RGB三通道先解釋一個基礎(chǔ)概念。屏幕畫面本質(zhì)上是一個巨大的像素點(diǎn)陣每個像素點(diǎn)顯示什么顏色由紅、綠、藍(lán)三個通道的亮度決定。三個通道的取值范圍都是 0 到 255對應(yīng)十六進(jìn)制就是 00 到 FF。比如純紅色是 R255、G0、B0用十六進(jìn)制表示就是 FF0000。純綠色是 00FF00純藍(lán)色是 0000FF。常見顏色都能用 6 位十六進(jìn)制串精確表達(dá)。GetColor 這個命令做的事情就是讀取指定屏幕坐標(biāo)上那個像素點(diǎn)的三通道值然后拼成一個文本串返回給你。這里有個很重要的認(rèn)知GetColor 返回的是文本串不是整數(shù)。很多新手第一次拿到返回值后試圖用“到整數(shù)”直接轉(zhuǎn)換結(jié)果發(fā)現(xiàn)轉(zhuǎn)出來亂七八糟就是因?yàn)閷Ψ祷刂殿愋屠斫忮e了。2.2 GetColor 返回串與 BGR/RGB 的順序陷阱我在不同版本的模塊上測試時發(fā)現(xiàn)同一個坐標(biāo)點(diǎn)不同版本返回的顏色串順序可能不一樣。有的返回 RGB 順序比如 112233 表示 R11、G22、B33有的返回 BGR 順序比如 112233 表示 B11、G22、R33。這個坑非常隱蔽。如果腳本里寫死了判斷邏輯一旦換了 DLL 版本顏色匹配直接失效。我的建議是拿到新環(huán)境后先做一次驗(yàn)證方法很簡單用系統(tǒng)畫圖軟件填充一塊純紅色區(qū)域顏色值設(shè)為 RGB(255,0,0)然后調(diào)用 GetColor 取那個點(diǎn)的顏色。如果返回 FF0000說明當(dāng)前版本返回的是 RGB 順序如果返回 0000FF說明是 BGR 順序。在封裝模塊時我建議不要直接透傳原始返回值而是在模塊內(nèi)部統(tǒng)一做一次格式轉(zhuǎn)換或命令選擇對外全部輸出一種約定好的順序通常是 RGB。這樣上層腳本就不會被版本差異影響。2.3 屏幕坐標(biāo)、窗口偏移與DPI縮放GetColor 接收的參數(shù)是屏幕坐標(biāo)以屏幕左上角為原點(diǎn)向右是 X 軸正方向向下是 Y 軸正方向。所以如果你要取的是某個軟件窗口內(nèi)部按鈕的顏色不能直接用窗口客戶區(qū)里的相對坐標(biāo)需要先拿到按鈕在窗口內(nèi)的位置再換算成屏幕坐標(biāo)。舉個例子窗口客戶區(qū)左上角的屏幕坐標(biāo)是 (winX, winY)按鈕在客戶區(qū)里的位置是 (btnX, btnY)那按鈕的實(shí)際屏幕坐標(biāo)就是 (winX btnX, winY btnY)。很多新手直接拿窗口控件坐標(biāo)去調(diào) GetColor取回來的自然不是期望的顏色。還有一個容易忽視的因素是 DPI 縮放?,F(xiàn)在 Windows 系統(tǒng)默認(rèn)可能開了 125% 或 150% 縮放如果程序沒有聲明 DPI 感知系統(tǒng)返回的邏輯坐標(biāo)和實(shí)際物理像素坐標(biāo)就會對不上導(dǎo)致取色位置偏移。遇到這種情況可以在程序啟動時調(diào)用系統(tǒng) API 聲明進(jìn)程 DPI 感知或者在模塊里對坐標(biāo)做一次縮放換算。2.4 單點(diǎn)取色的性能邊界GetColor 是逐點(diǎn)讀取速度不慢每次調(diào)用大約在毫秒級別但如果你寫一個循環(huán)去掃描上千個坐標(biāo)點(diǎn)累計耗時就會很明顯。實(shí)際項(xiàng)目里我用得比較多的是“定時檢測某個關(guān)鍵點(diǎn)顏色變化”比如每 200 毫秒取一次基本不會影響性能。如果需要在一個大范圍內(nèi)尋找某個顏色正確的思路是直接用大漠的 FindColor 命令讓底層去完成區(qū)域查找而不是自己寫雙層循環(huán)配合 GetColor 硬掃。封裝模塊時也應(yīng)該把命令分層基礎(chǔ)層放 GetColor上層再逐步封裝 FindColor 這類高效命令。3. 動手搭模塊骨架大漠對象的一生與初始化細(xì)節(jié)3.1 建一個易模塊工程先分清公開與私有在易語言里新建“易模塊”類型會生成一個 .ec 文件這個文件就可以被別人引用。模塊里可以存放子程序、全局變量、程序集變量等。關(guān)鍵點(diǎn)是“公開”屬性決定了子程序能否被外部調(diào)用。沒有勾選“公開”的子程序只能模塊內(nèi)部自己用外部項(xiàng)目根本看不到。我在設(shè)計模塊時有一個習(xí)慣內(nèi)部輔助函數(shù)統(tǒng)一加上“內(nèi)部_”前綴比如“內(nèi)部_轉(zhuǎn)換顏色格式”公開接口則使用自然語言命名比如“取顏色”“取顏色RGB”“顏色是否相似”。這樣引用模塊的時候彈出的命令列表一目了然不會把內(nèi)部實(shí)現(xiàn)細(xì)節(jié)暴露給使用者。易模塊里還可以放全局變量。對大漠封裝來說最核心的全局變量就是那個大漠對象整個模塊的所有命令幾乎都要依賴它。3.2 初始化、釋放大漠對象的生命周期管理大漠作為一個 COM 組件使用前需要先注冊 DLL然后在易語言里通過“對象”數(shù)據(jù)類型創(chuàng)建實(shí)例。我把這個過程封裝成兩個公開子程序一個負(fù)責(zé)初始化一個負(fù)責(zé)釋放。初始化子程序的主要流程是判斷外部是否傳入了 DLL 路徑如果沒有默認(rèn)取運(yùn)行目錄下的 dm.dll。調(diào)用系統(tǒng)命令注冊 DLL比如regsvr32 /s。等待注冊完成創(chuàng)建 COM 對象dm.dmsoft。創(chuàng)建后馬上檢查對象是否為空如果為空說明初始化失敗。返回邏輯型結(jié)果方便外部判斷是否繼續(xù)執(zhí)行。釋放子程序則比較簡單判斷對象非空后調(diào)用“釋放”方法把資源還回去。有些腳本寫完后不釋放對象短時間運(yùn)行看不出問題長時間跑或者頻繁創(chuàng)建銷毀時可能會遇到類似句柄泄漏的情況所以釋放這一步最好不要省。3.3 初始化失敗時的分層定位法如果大漠_初始化返回假先別急著懷疑代碼邏輯。按照下面這個順序排查現(xiàn)象常見原因排查方向注冊成功但創(chuàng)建對象失敗DLL 位數(shù)和系統(tǒng)不匹配檢查系統(tǒng)是 32 位還是 64 位更換對應(yīng) DLL注冊時提示權(quán)限不足非管理員權(quán)限運(yùn)行用管理員身份重新運(yùn)行一次DLL 文件存在但注冊沒反應(yīng)路徑帶了中文或空格把 DLL 放在純英文路徑下殺毒軟件彈出攔截提示DLL 被安全策略攔下確認(rèn)來源可靠后加入信任區(qū)創(chuàng)建對象成功但取色全空版本過老或?qū)ο蟊会尫艙Q一個穩(wěn)定版本檢查全局對象狀態(tài)多數(shù)情況下初始化失敗的根子不在代碼而在環(huán)境。尤其是 DLL 位數(shù)問題64 位系統(tǒng)上如果不小心拿了 32 位版本的 DLL注冊可以成功對象創(chuàng)建卻會失敗非常迷惑人。4. 取顏色接口的實(shí)現(xiàn)與兩個高價值擴(kuò)展4.1 基礎(chǔ)版取顏色子程序的完整代碼模塊骨架搭好后現(xiàn)在來實(shí)現(xiàn)核心的取顏色子程序。代碼如下.版本 2 .程序集 大漠封裝模塊 .全局變量 大漠對象, 對象 .子程序 大漠_初始化, 邏輯型, 公開 .參數(shù) DLL路徑, 文本型, 可空 .局部變量 目標(biāo)路徑, 文本型 目標(biāo)路徑 DLL路徑 如果真 (是否為空 (目標(biāo)路徑)) 目標(biāo)路徑 取運(yùn)行目錄 () “\dm.dll” .如果真結(jié)束 運(yùn)行 (“regsvr32 /s ” 目標(biāo)路徑, 假, 0) 延時 (500) 大漠對象.創(chuàng)建 (“dm.dmsoft”, ) 如果真 (大漠對象.是否為空 ()) 返回 (假) .如果真結(jié)束 返回 (真) .子程序 大漠_注銷, 公開 如果真 (大漠對象.是否為空 () 假) 大漠對象.釋放 () .如果真結(jié)束 .子程序 取顏色, 文本型, 公開 .參數(shù) 橫坐標(biāo), 整數(shù)型 .參數(shù) 縱坐標(biāo), 整數(shù)型 如果真 (大漠對象.是否為空 ()) 返回 (“”) .如果真結(jié)束 返回 (大漠對象.文本方法 (“GetColor”, 橫坐標(biāo), 縱坐標(biāo)))這里有兩個容易混淆的點(diǎn)。第一為什么用“文本方法”而不是“數(shù)值方法”因?yàn)?GetColor 返回的就是文本串。第二判斷對象是否創(chuàng)建成功用“是否為空 ()”這是一個邏輯判斷不是直接比較對象變量。我習(xí)慣在取色前做一次對象狀態(tài)檢查如果對象未初始化就直接返回空文本讓上層可以統(tǒng)一按照“空文本 取色失敗”來處理。4.2 高價值擴(kuò)展一統(tǒng)一輸出RGB順序的取顏色RGB前面提到不同版本返回順序可能不同。為了對外統(tǒng)一我封裝了一個“取顏色RGB”子程序。如果你的 DLL 版本支持 GetColorRGB 命令直接調(diào)用它最省事.子程序 取顏色RGB, 文本型, 公開 .參數(shù) 橫坐標(biāo), 整數(shù)型 .參數(shù) 縱坐標(biāo), 整數(shù)型 如果真 (大漠對象.是否為空 ()) 返回 (“”) .如果真結(jié)束 返回 (大漠對象.文本方法 (“GetColorRGB”, 橫坐標(biāo), 縱坐標(biāo)))如果手上版本不支持這個命令也可以手動轉(zhuǎn)換。比如 GetColor 返回的是 BGR 格式“BBGGRR”要轉(zhuǎn)成 RGB 格式“RRGGBB”可以通過取文本中間把三個分量分別拆出來再重新拼接。這個轉(zhuǎn)換過程在模塊內(nèi)部完成外部調(diào)用的人完全無感。轉(zhuǎn)換代碼大致思路如下 假設(shè)原始顏色串格式為 BBGGRR 藍(lán) 取文本中間 (原始顏色, 1, 2) 綠 取文本中間 (原始顏色, 3, 2) 紅 取文本中間 (原始顏色, 5, 2) 轉(zhuǎn)換結(jié)果 紅 綠 藍(lán)提示轉(zhuǎn)換前最好先確認(rèn)當(dāng)前 DLL 返回的到底是 RGB 還是 BGR不然會白忙一場。4.3 高價值擴(kuò)展二帶容差的顏色相似判斷實(shí)際測試中你會發(fā)現(xiàn)同一個坐標(biāo)點(diǎn)的顏色并不是永遠(yuǎn)不變的。屏幕刷新、字體渲染、顯卡色彩管理都可能導(dǎo)致顏色產(chǎn)生輕微波動。如果腳本用“顏色值精確相等”來判斷很容易失靈。所以我封裝了一個“顏色是否相似”的判斷命令。核心邏輯是把兩個顏色串分別拆成 RGB 三個分量計算每個分量的差只要三個分量的差都小于設(shè)定的容差值就認(rèn)為顏色相似。這個方法比“整串相等”實(shí)用得多。做狀態(tài)監(jiān)測時我經(jīng)常用它配合 GetColor 寫等待邏輯取目標(biāo)坐標(biāo)顏色和目標(biāo)顏色比較如果相似就認(rèn)為狀態(tài)到位否則繼續(xù)等待。4.4 模塊接口命名與約定的心得封裝模塊到最后很容易攢出一堆子程序。這里分享一個我摸索出來的約定所有公開命令要么以“取”開頭表示讀取要么以“是否”開頭表示判斷保持行為可預(yù)測。失敗返回統(tǒng)一約定文本型返回空文本邏輯型返回假。所有坐標(biāo)參數(shù)用整數(shù)型不限制為正數(shù)方便處理多顯示器下的負(fù)坐標(biāo)。模塊內(nèi)部每個子程序都寫上簡短注釋說明參數(shù)含義和返回值約定。這套約定看起來簡單但實(shí)際用起來非常舒服。過幾個月再回來寫新腳本翻模塊命令列表就能快速恢復(fù)記憶不需要重新讀源碼。5. 實(shí)測驗(yàn)證做個實(shí)時取色標(biāo)簽看看顏色到底穩(wěn)不穩(wěn)5.1 準(zhǔn)備一個最簡單的取色器窗口光寫完模塊還不夠得實(shí)際跑一下才知道有沒有問題。我建了一個測試窗口放了三個控件一個按鈕、一個標(biāo)簽、一個時鐘。按鈕負(fù)責(zé)手動取色標(biāo)簽負(fù)責(zé)展示結(jié)果時鐘負(fù)責(zé)每 200 毫秒自動取一次色觀察顏色變化。窗口創(chuàng)建完畢后先調(diào)用大漠_初始化。如果初始化失敗就彈提示框退出避免后面調(diào)用一路報錯。代碼如下.版本 2 .程序集 窗口程序集_啟動窗口 .程序集變量 上次顏色, 文本型 .子程序 __啟動窗口_創(chuàng)建完畢 如果真 (大漠_初始化 () 假) 信息框 (“大漠模塊初始化失敗”, 0, ) 返回 () .如果真結(jié)束 上次顏色 “” .子程序 _按鈕_取色_被單擊 .局部變量 顏色值, 文本型 顏色值 取顏色 (200, 200) 如果真 (顏色值 “”) 信息框 (“取色失敗請檢查對象狀態(tài)”, 0, ) 返回 () .如果真結(jié)束 標(biāo)簽_結(jié)果.標(biāo)題 “當(dāng)前顏色” 顏色值 上次顏色 顏色值 .子程序 _時鐘_取色_周期事件 .局部變量 當(dāng)前顏色, 文本型 當(dāng)前顏色 取顏色 (200, 200) 如果真 (當(dāng)前顏色 “”) 返回 () .如果真結(jié)束 如果真 (上次顏色 ≠ “” 且 當(dāng)前顏色 ≠ 上次顏色) 標(biāo)簽_結(jié)果.標(biāo)題 “顏色變化舊” 上次顏色 “ 新” 當(dāng)前顏色 .如果真結(jié)束 上次顏色 當(dāng)前顏色5.2 完整測試代碼與預(yù)期效果運(yùn)行這個測試程序點(diǎn)擊按鈕后標(biāo)簽會顯示坐標(biāo) (200,200) 的顏色值。接著把鼠標(biāo)移動到其他區(qū)域再點(diǎn)按鈕標(biāo)簽內(nèi)容會跟著變化。時鐘開啟后如果 (200,200) 這個點(diǎn)的顏色發(fā)生改變標(biāo)簽會自動更新提示。為了驗(yàn)證 BGR/RGB 順序我在系統(tǒng)畫圖里填充了一塊純紅色區(qū)域然后用這個取色器去取色??吹椒祷刂凳?FF0000 的時候我就知道當(dāng)前 DLL 版本返回的是 RGB 順序。這個驗(yàn)證步驟建議每個新環(huán)境都做一遍。5.3 實(shí)測中看到的顏色抖動現(xiàn)象在我測試時標(biāo)簽顯示的顏色偶爾會在幾個相近值之間跳動。原因很簡單某些軟件界面會做漸變或者按鈕 hover 高亮效果鼠標(biāo)輕輕劃過顏色就變了。另外部分顯卡開啟了色彩抖動也會導(dǎo)致像素點(diǎn)顏色發(fā)生微小波動。這個現(xiàn)象印證了“顏色相似判斷”的必要性。直接比較顏色串是否相等在這種環(huán)境下很容易誤判。使用帶容差的相似判斷比如容差設(shè)為 10 或者 15就可以把這種微小波動過濾掉同時不會誤判成完全不同的顏色。6. 封裝備忘錄易語言調(diào)用大漠時的經(jīng)典坑與排查順序6.1 “創(chuàng)建對象失敗”明明代碼沒問題是環(huán)境問題我印象最深的一次排查是這樣的代碼在同事的機(jī)器上運(yùn)行正常換到我這邊就一直報初始化失敗。折騰了兩小時最后發(fā)現(xiàn)同事的機(jī)器是 32 位系統(tǒng)而我這邊是 64 位系統(tǒng)兩個系統(tǒng)需要對應(yīng)不同位數(shù)的 DLL。所以如果你確認(rèn)代碼邏輯沒問題先去檢查系統(tǒng)和 DLL 的位數(shù)匹配情況。另外注冊 DLL 需要管理員權(quán)限如果程序不是以管理員身份運(yùn)行注冊過程可能被系統(tǒng)攔截注冊結(jié)果卻顯示成功等到創(chuàng)建對象時才真正報錯。還有一個小細(xì)節(jié)DLL 路徑里不要有中文或特殊字符。某些系統(tǒng)環(huán)境對調(diào)用外部命令傳中文路徑的處理不太穩(wěn)定放到純英文目錄下更穩(wěn)妥。6.2 取色結(jié)果全為空先檢查坐標(biāo)和對象狀態(tài)如果初始化成功但取顏色返回空文本我先檢查兩件事坐標(biāo)是否超出屏幕范圍以及對象是否在之前的某次操作中被意外釋放了。屏幕坐標(biāo)可以取負(fù)值比如多顯示器場景下副屏在主屏左側(cè)時副屏上的點(diǎn)是負(fù)坐標(biāo)。如果你的模塊里把坐標(biāo)參數(shù)限定成了非負(fù)整數(shù)型這時候就會出問題。所以封裝時坐標(biāo)參數(shù)最好用“整數(shù)型”不要加非負(fù)限制。另一個情況是對象被釋放了。有些代碼可能在腳本運(yùn)行中途調(diào)用了“大漠_注銷”后面的取色命令再執(zhí)行時自然會失敗。模塊內(nèi)部雖然做了對象狀態(tài)檢查返回空文本但不代表不會有“每個命令都返回空”的現(xiàn)象出現(xiàn)排查方向要放在對象生命周期上。6.3 多顯示器負(fù)坐標(biāo)與版本差異多顯示器環(huán)境是另一個高頻故障點(diǎn)。Windows 的主顯示器默認(rèn)坐標(biāo)原點(diǎn)在左上角副屏如果位于主屏左側(cè)或上方它的坐標(biāo)區(qū)域就會出現(xiàn)負(fù)值。早期有些版本的 DLL 對負(fù)坐標(biāo)支持不好取色會直接失敗或返回錯誤結(jié)果。遇到這種情況先確認(rèn) DLL 版本是否支持負(fù)坐標(biāo)。如果不支持可以把所有坐標(biāo)整體做一次偏移把副屏的負(fù)坐標(biāo)轉(zhuǎn)換到正坐標(biāo)區(qū)域再取色。不過這種做法會犧牲一點(diǎn)直觀性模塊設(shè)計時要提前想清楚到底采用“統(tǒng)一偏移”還是“直接支持負(fù)坐標(biāo)”。6.4 位數(shù)、版本和殺毒攔截的組合拳最后說一個比較綜合的坑程序在 32 位模式下編譯一切正常換成 64 位就各種報錯。這通常不是代碼的問題而是 DLL 版本對編譯目標(biāo)不兼容。建議固定一套已經(jīng)測試通過的 DLL 版本不要頻繁升級。安全軟件攔截也是常見問題。大漠這類 DLL 因?yàn)橐?COM 組件、寫入注冊表經(jīng)常觸發(fā)安全軟件的敏感行為提示。如果確認(rèn) DLL 來源可靠可以把它加入信任區(qū)。這里也想提醒一句這類圖色自動化技術(shù)建議用于桌面軟件測試、界面狀態(tài)監(jiān)測等正常場景不要用在破壞他人軟件或服務(wù)條款不允許的領(lǐng)域。寫在最后的一點(diǎn)實(shí)戰(zhàn)建議從第一次接觸 GetColor 到現(xiàn)在我最大的體會是封裝模塊這件事前期多花一小時后期能省十小時。GetColor 只是整個模塊里的一個小命令但把它吃透之后你會自然理解大漠底層命令的調(diào)用套路之后再封裝找色、找圖都是順?biāo)浦鄣氖?。最后分享一個實(shí)用小技巧測試取色功能時可以做一個懸浮小窗口鼠標(biāo)移動時實(shí)時顯示當(dāng)前坐標(biāo)和顏色值。我后面把這個取色器做成了自己日常調(diào)試的常備工具比單步調(diào)試舒服太多。等你把模塊的基本命令封裝好建議也做一個這樣的取色器邊寫邊測很多問題一眼就能看出來。