Excel閱讀模式/單元格行列指示/聚光燈開發 技術要點再分享


 

1. 引言

  文題中所謂技術要點再分享,本意是想在大神Charltsing Liu的博文“簡單介紹Excel單元格行列指示的實現原理(俗稱聚光燈功能)”的基礎上寫一點個人開發體會。寫本文的初衷有三點,一是自己學習的一個記錄。二是,盡管Charltsing Liu公開了原理,還是鮮有人能夠開發出來,准確的來說免費的插件里頭只有博主他自己的比較完美的實現了,收費的里面也只有Kutools,市面上的聚光燈(Excel單元格行列/閱讀模式)實在質量不咋滴。三是,很多Excel插件開發者,尤其VBAer,想在自己的工具箱里加入這么一個功能,但實際往往止步於Charltsing Liu的原理,只能望洋興嘆。基於此,本文權當是Charltsing Liu大神的狗尾續貂。

  有過EXCEL插件開發經驗或者Excel中重度用戶可能都知道“Excel閱讀模式“或叫“行列指示”or“聚光燈”,個人認為行列指示似乎更貼切。很多插件里也都能看到這個功能。 比如“易用寶”,“方方格子”“Excel催化劑”,“uuoffice”,“DnaTools”,“Kutools for Excel(收費)”等等(若我沒記錯,這些都有,總之,凡是有這一功能的幾乎我都有測試過)。

  所謂Excel閱讀模式/行列指示/聚光燈這樣一個功能, 其本質就是“實現在選中的單元格所在的行列上加上一個可視化的標記以使其行列信息突出顯現。

  這樣一個功能在實際中是非常有用的(據說WPS有原生),尤其當面對表格行列外觀設計區分度不高,數據量又較多,需要查閱數據和補錄數據等操作的時候。如下兩圖,便可看出。

  一種這樣的功能,其實現原理,Charltsing Liu在其博文中已有較為概括性的闡述,可以參考閱讀。本文再次分類簡述如下,共有5種實現方式:

初級VBAer方式

  利用excel選擇事件,動態改變target的底色。(影響既定格式,對行列數據可能造成遮罩。)

中級VBAer方式

  利用excel 動態插入線段,在事件中動態刪除更改線段的位置,即所謂線段指示。(可能影響操作,可能線段被用戶無意選中,影響用戶體驗。)

高級VBAer方式

  利用excel條件格式,通過設置指示活動單元格行列的格式達到目的。條件格式影響既定的條件格式,也會影響Excel某些原生功能的使用。

這里有個外文網站,有興趣的可以戳閱,里面有xlsm供下載:http://www.tushar-mehta.com/publish_train/xl_vba_cases/0121%20highlight%20row%20and%20col%20of%20selected%20cell.shtml

大神級別——這樣做

  通過一序列WindowsAPI獲得相關坐標,基於GDI技術,在Excel7窗口上繪圖實現。然而這只能在2010版本之前的excel上實現,具體原因是EXCEL2013改變了刷新方式,會導致這種方式的實現會閃瞎眼。

真大神級別——這樣做

  這種技術稱為HUD技術,所謂HUD技術就是在正常畫面上,疊加一個透明或者半透明效果的窗口,用來顯示一些實時的數據。玩過飛行模擬之類游戲的,都會看到這種效果。很多電影的炫酷特效畫面也經常能看到。(此段原文見liucaq博文)。這種疊加的窗體是相對獨立存在的,只有加上一些特定的消息處理,限定處理窗口與宿主窗口的關系,是完全不會影響原宿主窗口的。在Excel閱讀模式/單元格行列指示/聚光燈中具體實現可概括為:為Excel增加一個透明且鼠標可以穿透的層級窗體,通過計算excel單元格行列的位置等確定窗體的位置,然后在事件中動態更改窗體的外觀(異形窗體)或者直接在窗體上通過GDI進行繪制顯示標記。

  以上這5種實現方式均能不同程度的解決實際問題,然而,個人以為,這個功能的實現方式必須滿足以下5個條件,才能算是一種比較完美的解決方案

     第一:不影響活動行列的原數據的閱讀。

    第二:不影響既定的Excel單元格格式。

    第三:不影響EXCEL原生的功能使用。

    第四:適應表格的各種視圖模式,比如拆分,凍結模式,Zoom,以及各種操作。

    第五:最大的兼容不同的Excel版本。

  顯而易見,只有HUD技術的實現能滿足這五個條件。

2.閱讀模式/行列指示/聚光燈的優秀作品品評

  個人認為,目前以這種方式實現的作品比較知名且使用較為完美的有DnaTools(大神liucaq的作品,免費),kutools for EXCEL(收費),Uuoffice(免費),最后的就是當然就是本人的PowerExcel Helper。

  DnaToolsv2.9.7.2) 的行列指示,速度非常快,作者是真大神級別^_^。據說有很多國內第一或者填補了空白,真假難辨(^_^,請各位自辨)。目前版本我測試出的bug是 影響Excel插入圖表后的圖表菜單的使用,且功能開啟后,插入圖標,新建窗口,有卡屏的bug。另外還有個線段位置計算的問題。

  Kutools for EXCEL,是個收費的插件,其閱讀模式,我原來一直覺得是最完美的實現。包括運行速度等都不錯,如果苛刻地說,啟動有點慢。直到有個網友,提供了一個工作文檔給我,反饋說kutools在他這個文檔里有個嚴重的bug,會導致Excel奔潰,才斷送了在我心目中的最完美實現。

  Uuofifce1.6里的閱讀模式呢,bug稍微多一些,我也給作者反饋過。比如有些消息的捕獲不夠准,導致有延遲的現象存在,另外在窗口有拆分和凍結的情況下表現也不是很好,作者似乎沒有考慮這些情況。縱使如此,本人覺得依然是比較優秀的插件,而且開發者幾乎不打廣告,比較低調。

下方這段廣告預警,謹慎閱讀^_^^_^^_^

       此部分最后,不得不談下我的作品PowerExcel Helper v1.00中的“行列指示(聚光燈)”。就目前測試情況來說,沒有上面三款插件里提到的bug,相比之下,算是最完美無暇的了。(牛皮就是吹的 ^_^),速度也一樣OK。

 

3.開發分享——技術要點

  最后,也是本文最重要的部分,來談一談實現這個功能的幾點體會。Liucaq大神說過的,盡量不再重復,核心技術或者要點,概括起來有:

  ◆1.創建的載體窗體,最重要的是要處理好它與宿主窗口(xlmain?xldesk?excel7?)的關系,比如父子?比如從屬?等關系,記得我在QQ群里(Office developer開發者550672198)里提過。這個是有api可以做到的。如果不去處理這個關系,就要花費很多代碼去攔截消息。很費力。

  ◆2.就是如何使用Excel提供的函數Point sToScreenPixelsX/Y來計算單元格相對屏幕像素的位置。我發現幾乎很少人知道怎么使用這個函數,至少我真沒有發現。在這里說下,要使用Point sToScreenPixelsX/Y進行excel單元格或表格可視區域進行計算,它的父級是Pane而不是Window,這樣的原因可能導致了有插件沒有去考慮窗格拆分凍結的情況。也直接影響了EH論壇帖子“[原創] 【重磅發布】:聚光燈——我的加載宏系列小工具【單元格小工具】之四”作者對於Zoom情況的計算,最后其工具妥協於僅適用Zoom=100%的情況使用,另外該文作者也沒有進行消息處理。(當然,或許作者是有所保留吧,如是,請原諒我的愚鈍)。

  ◆3。在多窗格計算的時候不要過於依賴excel對象提供的函數,否則有意想不到的bug驚喜,而且你很難調試及預想到。

  ◆4.不同版本的EXCEL子窗口的消息還不太一樣,這點也很讓人費心。開發者多關注這個消息WM_MDIGETACTIVE。順提一句,某些插件的bug很有可能是WM_STYLECHANGGED消息造成。

  ◆5.VBA實現此功能要相對容易得多,因為可以忽略處理窗口關系。若想嘗試開發,可以從這句去得到啟示。

  ◆6.消息的攔截光有HOOK 還不行,得接管子窗口的WndProc過程兩者相結合。因為鼠標在EXCEL窗口外發生MOUSEWHEEL時候,是沒法單純hook直接處理的。當然如果不接管WndProc,單獨用Hook也是沒有問題的,32bit/64bit都能支持。只是有個小Bug,完全不影響使用。若用Hook,請查看WH_CALLWNDPROCRET。

  ◆7.要注意C#在32位/64位平台使用WindowsApi時平台指針地址和委托的轉換。

 

  以上七點已經接近開源了,如還不夠用,請參看EH論壇帖子“[原創] 【重磅發布】:聚光燈——我的加載宏系列小工具【單元格小工具】之四Charltsing Liu的博文

  【總結】

  不少人通過QQ私聊問我能不能直接給他源代碼,私以為,有了Charltsing Liu大神的實現原理一博文和本文的七條提示,實現閱讀模式/行列指示/聚光燈之類功能,應該沒有難處了。只需要你有足夠的耐心和鑽研勁,技術能力總是會得到逐步提升的。

  最后感謝Charltsing Liu大神在開發交流中給予的幫助支持,圍觀者應該多向他們這類人學習,不斷提升技術。

  另外,還不得不提下,EH論壇帖子“[原創] 【重磅發布】:聚光燈——我的加載宏系列小工具【單元格小工具】之四”的帖主ggmmlol(excelhome注冊網名),這篇帖子很想詳細的講述了開發的1/3的內容,正是有了這篇帖子的指引,才促使我去學習開發本文的功能,也才有動力去翻閱各種資料(耗時近一個月的周末時間)。再次感謝ggmmlol,為技術分享精神點贊。

文末來個小小彩蛋吧,給有興趣的VBAer提個idea以簡單的優化實現這個功能:利用選擇事件,添加刪除shape(線段或者半透明的矩形),然后hook消息,當用戶鼠標選中了這些特定的shape的時候,直接刪除。這樣的好處時,可以不用處理WM_SIZE,WM_Move等繁瑣的消息。Shape的位置也可以不用轉換屏幕坐標。也不影響表格其他的功能使用。代碼簡單了很多。成本極低,只需要學習Hook的使用。個人覺得理論是可行的。如有大神覺得idea太Low,請隨意拍磚,不要客氣。

 

       聲明:本文用到的詞匯如初級VBAer、大神級等,表述的方式而已,沒有貶低用意。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM