[開源] KumquatRoot2 - 本地文件查找工具


KumquatRoot2 - 本地文件查找工具

 

 

剛學習 C++ 不久, 這個小工具也算是對 C++ 的第一次實戰演練, 采用 wxWidgets 作為圖形庫, 僅僅調用了 Windows 的兩個 API, 一個是 ShellExecute 函數, 另一個是 WinExec 函數, 理論上稍加改動即可輕松移植到其他平台上。

完成了第一個 C++ 小工具, 心里還是十分高興的, 因此十分希望能夠與大家分享在這次 coding 中遇到的一些問題。
    
    


一、 出師不利
    由於 C++ 和 wxWidgets 都是剛接觸不久, 再加上 wxWidgets 中文資料並不多, 在網上找了好久只找到了一本不是太完整的 wxWidgets 的教程, 內容較少, 所以項目剛開始時就遇到了一些麻煩。
    
    失敗的界面布局
        一般來說, 一個普通的窗口程序都允許用戶對程序的窗口進行大小的調整, 其中窗口中的控件位置以及大小也能根據窗口大小的調整進行自身的調整, 但是由於對 wxWidgets 智能布局的不熟悉, 就決定自己來實現對窗口的智能布局, 一是不想固定了窗口的大小, 因為固定的太小了, 搜索的結果橫向顯示不完整, 二是想體驗下對窗口自定義實現智能布局的復雜度。
        
        通過 EVT_SIZE 事件來進行子窗口控件的相關調整, 但是到后來發現這種做法是十分愚蠢和錯誤的, 隨着控件的不斷增多, 需要調整的控件位置、大小也越來越多, 到最后長長的好幾屏代碼都是來響應對控件的調整的。
        
        最終的解決方案: 查閱官方手冊、google it來學習 wxWidgets 的智能布局類, wxSizer, 使用其中的 wxBoxSizer 類來實現對窗口的布局。
        
        wxBoxSizer 是一個允許水平/垂直的布局類, 他僅允許垂直/水平布局, 不過這已經足夠了, 一般來說, 任何一個常規界面都可以通過不斷的布局嵌套來完成更加復雜的布局。
        
        對於 wxBoxSizer 布局的詳細使用, 筆者將會在接下來幾天對項目知識點的整理中發布在博客中。
        
        
        


        
二、全部重寫
    當代碼越寫感覺越糟糕的時候, 心情自然是越寫越差的, 在 這個月的 4 號終於受不了這種感覺了, 立即將項目從 github 上銷毀, 本地將項目文件夾打包到 Backup, 重新在 github 上建立項目, 重新建立工程, 一切重寫。有了第一次失敗的經驗, 寫起來自然就順暢多了, 但還是遇到了幾個技術上的問題。
    


    1>. 定時器 wxTimer 和 多線程 wxThread
        在找到的這本中文教程上有關多線程編程的建議時有這句話引起了我的注意:"多線程的替代方案  - 如果線程使用的復雜性讓你感到氣餒,也許你可以嘗試一些簡單的替代方案,比如使用定時器,空閑時間處理或者兩者一起使用. "。
        
        正是由於這句話, 讓我足足糾結了一個晚上。不能怪作者, 是我理解錯了。
        
        首先來介紹下這個搜索工具的工作原理, 目前的設計是將整個的搜索過程分為兩部分, 一是用戶無法直接看到的工作部分, 也就是程序背后的文件統計、分析、匹配工作, 另一部分就是用戶可以看到的部分, 軟件 UI 統計部分, 在搜索過程中, 程序會顯示一個模態對話框提示搜索正在進行, 並且不斷更新當前一共搜索了多少文件, 有多少個符合條件的。
        
        那么這個過程就可以看做是由兩個函數來進行, 一個負責搜索, 另一個負責更新UI, 既然那本書上說 "也許你可以嘗試一些簡單的替代方案,比如使用定時器", 還真嘗試了, 定時器分為一次性定時器(只提醒一次)和常規的間歇提醒類型的定時器, 那么根據這樣來說, 這不正好符合要求么, 一次性的定時器用來負責提醒下搜索函數的工作, 間歇型的定時器負責來更新 UI 上的統計數據, 想的確實挺完美的。
        
        當真這樣進行實現時問題就來了, 一次性定時器提醒搜索函數后, 搜索函數開始工作, 但是負責更新 UI 的函數並不能做出按照 150 毫秒/次的正常更新統計數據工作, 預設間隔是 150 毫秒, 但是即便等好幾十秒也沒見到 UI 上的統計數據更新, 直到搜索函數運行結果后這邊的統計線程才緩緩來遲進行更新最后的統計數據。顯然這樣做是錯誤的, 原因經過一番推理和驗證后得出了結果:


            wxTimer 啟動出來的函數同屬於一個線程, 當 搜索函數啟動后, 一直陷入查找文件、打開文件、匹配文件的循環中, 不到搜索完畢另一個負責更新UI的函數是無法開始工作的, 界面也不會有響應, 因為正常的事件循環被阻止掉了。
            
        當初就是誤認為 wxTimer 設計器會將這些函數放在不同的線程中才決定這么干的, 不過現在看起來也挺好, 起碼驗證了一個道理: "實踐是檢驗真理的唯一標准"。
        
        


    2>. 線程的終止
        若用戶在搜索過程中不要進行搜索了, 需要取消這次任務, 那么必然需要控制下線程使其結束工作, 搜索的過程就是一個 while 循環的過程, 因此退出 while 循環讓函數自行結束自然就達到了退出線程的目的, 在這次線程的控制中, 筆者使用的是通過一個控制 bool 型的 thread_stop 變量的值來實現的, 這個值在對話框類中, 初始值為 false, 通過引用傳遞到搜索線程, 在搜索的 while 循環中:
        

        while( dirItems.GetCount() && ( !threadstop ) )            //當目錄隊列不為空時且 !threadstop 值為真時執行
        {
            //匹配的過程
        }

       
        在 UI 部分, 當用戶點擊停止時, 就將 threadstop 的值改為 true, 這樣 while 的條件變為假, 就不再執行函數體, 搜索線程函數退出, 終止搜索。
        
        線程的暫停與繼續相對來說就好實現的多了,

            wxThread::Pause()         //用來暫停線程
            wxThread::Resume()        //用來恢復線程


            
            
    3>. 向窗口發送消息
        當搜索完成后, 需要通知 UI 部分說停止更新界面的計時器以及滾動條還有相關按鈕的標簽文字改變, 例如當搜索完成后, 停止按鈕上的文字就由 "停止" 變成了 "完成!", 要完成這個步驟有兩種解決方案, 一是將這些窗口的控件以及定時器通過指針/引用傳遞到線程, 由線程在返回前改變這些控件/定時器的狀態, 但這樣做實屬麻煩。 第二種方案就是當搜索要完成時向對話框的消息隊列中插入一個事件, 由對話框的事件綁定來完成搜索結束后的相關處理。
        
        wxPostEvent函數是用來插入消息的函數之一, 他的函數原型如下:

            void wxPostEvent(wxEvtHandler *dest, wxEvent& event)


        通過函數原型可以看到, 該函數需要一個事件句柄和消息類型, 要解決這個事件句柄只需要將需要接受事件的窗口指針傳入進來, 然后 wnd->GetEventHandler() 即可得到該窗口的事件句柄。
        
        對於消息類型, 這里使用的是一個虛擬的按鈕消息,

            wxCommandEvent event( wxEVT_COMMAND_BUTTON_CLICKED, VIR_BTN_DONE );

        實際上這個按鈕並不存在, VIR_BTN_DONE 就是這個按鈕的 ID, 他是一個自定義的常量, 但是通過 wxPostEvent 將該事件插入到消息隊列后, 目標窗口就能接受到來自該 ID 按鈕的消息, 即便實際上他是不存在的, 進而完成相關的處理。
        

        //在線程中向目標窗口插入事件
        wxCommandEvent event( wxEVT_COMMAND_BUTTON_CLICKED, VIR_BTN_DONE );
        wxPostEvent( wnd->GetEventHandler(), event );

 





三、其他一些瑣碎的知識點分享
    1>. 取出 wxListCtrl 選中行中的某列元素的文本

    unsigned long index = resList->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED );    //獲取當前選中的行的下標
    wxListItem item;
    item.SetMask(wxLIST_MASK_TEXT);
    item.SetId(index);
    item.SetColumn(1);            //取出選中行的第二列中的文本, 注: 下標以0開始
    resList->GetItem(item);
    return item.GetText();

 

 
    2>. 兩個 Windows API
        ①. ShellExecute
            ShellExecute 的功能通常被用來運行一個外部的程序, 或者打開一個文件/文件夾等操作, 詳細的作用以及用法見百科: ShellExecute
            一個通過 ShellExecute 調用與該類型文件相關聯的應用程序進行打開的示例:

                if( ShellExecute( NULL, _T("open"), getListSelectedPtah(), "", "", 1 ) <= (HINSTANCE)32 )        //返回值小於或等於32時表示失敗
                    wxMessageBox( _T("未找到有效的打開方式!"), _T("打開失敗"), wxOK|wxICON_INFORMATION );

 

        ②. WinExec 也可以用來運行指定程序, 例如將某個完整路徑的文件在文件夾中顯示:

            WinExec( "explorer /select, " + getListSelectedPtah(), SW_NORMAL );

            返回值大於 32 時表示成功。
            
            


    3>. 文件查找的核心函數, 對文件/文件夾的操作
    
        ①. wxWidgets 提供的用來遍歷目錄的類 wxDir
            [譯] wxWidgets - wxDir
            
        
        ②. 使用 wxDir 遍歷目錄的示例
            [代碼分享] wxWidgets - wxDir 遍歷文件
            [代碼分享] wxWidgets 非遞歸方式遍歷文件


        ③. wxWidgets 提供的一部分對文件/文件夾操作函數
            [譯] wxWidgets - File functions - 文件/文件夾函數
            
    


凌晨三點了, 就先寫到這, 其實內心還有很多這次學習到的知識想要與大家分享, 最近幾天筆者會繼續整理下本次項目中用到一些知識點較為系統的發表在博客里, 有努力就會有收獲, 經過這十多天的努力, 這個小軟件終於完成了!
   


軟件名稱: KumquatRoot2 - 橘根文件搜索
軟件類型: 磁盤輔助
運行平台: Windows
開發語言: C++
圖形庫: wxWidgets

開發環境: Microsoft Visual C++ 6.0
軟件介紹: 按指定規則查找磁盤中的文件。無需安裝, 綠色零配置, 支持匹配文件內容、支持正則表達式。

軟件截圖:


    
開源協議: GNU GPL v3 ( http://www.gnu.org/licenses/gpl-3.0.html )

項目下載: https://github.com/mrwid/KumquatRoot2

軟件下載: http://files.cnblogs.com/mr-wid/KumquatRoot2.zip


使用介紹:
    首先通過 "瀏覽(B).." 按鈕選擇需要搜索的目錄, 然后配置相關的查找條件:
        1. "匹配文件名稱", 按照文件名進行匹配, 在輸入框中輸入文件大致名稱或正則表達式, 點擊 "啟用" 復選框后開啟該搜索條件;
        
        2. "匹配文件內容", 按文件內容進行匹配, 在輸入框中輸入文件內容關鍵詞或正則表達式, 點擊 "啟用" 復選框后開啟該搜索條件;
        
        3. "選擇匹配模式", 當選擇 "普通模糊匹配" 時表示常規的文件查找, 輸入框中的內容作為查找關鍵詞; "正則表達式匹配" 表示將輸入框中的內容作為正則表達式對文件/文件名進行匹配;
        
        4. "按擴展名過濾", 輸入框中輸入以空格隔開的文件擴展名, 可以帶擴展名的前的點'.'號, 也不可以不帶, "過濾以上擴展名"表示不對以上擴展名結尾的文件進行匹配; "僅匹配以上擴展名"表示僅查找以以上擴展名作為文件名結尾的文件。
        
        5. "開始搜索(S)", 按照以上設置的條件對指定目錄中的文件進行匹配。
        
        
    在搜索結果欄中, 可用右鍵彈出右鍵菜單對搜索到的文件進行進一步的操作, 右鍵菜單中的選項包括:
        1. 打開文件(O)               : 使用與該類型文件相關聯的應用程序進行打開;
        2. 打開文件所在目錄(P)        : 將該文件所在的文件夾顯示出來, 並將該文件以高亮形式標注。
        3. 另存為...(S)              : 將文件保存到其他文件夾, 源文件不刪除;
        4. 刪除文件(D)               : 將該文件從磁盤中刪除;
        5. 關於 KumquatRoot2         : 對 KumquatRoot2 的相關介紹。
        
        
特別提示:
    由於系統的權限設置, 在磁盤中存在一些普通應用程序無法訪問的文件夾, 當 KumquatRoot2 嘗試搜索到這個權限不足的文件夾時會提示無法訪問並跳過, 點擊 "Ok" 按鈕關閉錯誤提示對話框。
    

   當使用文件內容進行匹配時, 對於二進制文件, 程序將采取主動跳過的方案, 不會讀取完整的內容進行匹配。


    
其他說明:
    KumquatRoot2 是 KumquatRoot1.0 重構版, KumquatRoot1 由 Python 語言進行編寫, (詳細介紹: http://www.x86pro.com/kumquat/kumquatroot/ ) KumquatRoot2 在 上一版本的功能的基礎上使用 C++ 語言進行全部重寫, 大大減少了軟件體積以及附加文件數量, KumquatRoot2僅有一個獨立的 exe 可執行文件, 零配置, 完全綠色、開源。其整個項目托管在 github 上。
    
    
    如果您對該軟件有新的建議和意見, 歡迎留言, wid 會盡最大努力在以后的版本中對軟件進行改進和提高。
    
    

 

 

再長的路, 一步步也能走完; 再短的路, 不邁開雙腳也無法到達。    

 

 


--------------------


    
wid, 2013.03.11


 


免責聲明!

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



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