<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    如鵬網(wǎng) 大學(xué)生計(jì)算機(jī)學(xué)習(xí)社區(qū)

    CowNew開(kāi)源團(tuán)隊(duì)

    http://www.cownew.com 郵件請(qǐng)聯(lián)系 about521 at 163.com

      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      363 隨筆 :: 2 文章 :: 808 評(píng)論 :: 0 Trackbacks
     

    《網(wǎng)絡(luò)吸管》開(kāi)發(fā)手記

    網(wǎng)絡(luò)確實(shí)是個(gè)好東西,文章呀,圖片呀什么的都很吸引人。每次上網(wǎng)都能滿載而歸,但是這些資料的收集過(guò)程卻很麻煩。對(duì)于好文章,每次都要復(fù)制、粘貼地在記事本和IE之間切換多次才能保存下來(lái),而且說(shuō)不定什么時(shí)候遇到那種怎么復(fù)制也復(fù)制不下來(lái)的防復(fù)制網(wǎng)頁(yè);對(duì)于圖片也要點(diǎn)右鍵,選擇“圖片另存為”,再點(diǎn)確定才可以,遇到文件重名問(wèn)題還要重命名。上網(wǎng)的興致全被打亂了。網(wǎng)上雖然也有“網(wǎng)文快捕”之類的小軟件,但是由于不是為自己“量身定做”的,所以用起來(lái)也不是很順手。既然這樣,就自己動(dòng)手做一個(gè)吧,“自己動(dòng)手豐衣足食”嘛!說(shuō)干就干!

    設(shè)計(jì)思想很簡(jiǎn)單:監(jiān)視剪貼板,當(dāng)發(fā)現(xiàn)剪貼板中有新內(nèi)容時(shí),就根據(jù)內(nèi)容是文字還是圖片來(lái)決定不同的保存方式。

    如何監(jiān)視剪貼板呢?很自然地想到放一個(gè)定時(shí)器,每隔一段時(shí)間檢測(cè)一個(gè)剪貼板,將剪貼板地內(nèi)容于上次檢測(cè)地內(nèi)容相比較,如果不同,就說(shuō)明剪貼板的內(nèi)容有變化。但是這樣效率太低了,并且定時(shí)器的時(shí)間間隔也不好把握,間隔太短會(huì)降低系統(tǒng)的效率,而間隔太長(zhǎng)就有可能漏掉復(fù)制的內(nèi)容。這讓我想起了CPU與外設(shè)之間通訊方式中的查詢方式,那么有沒(méi)有一種像CPU與外設(shè)之間的中斷方式的東西呢?啟動(dòng)MSDN,搜索ClipBoard,呵呵!終于找到了!是什么呢?聽(tīng)我慢慢道來(lái)!

    為了使應(yīng)用程序能自動(dòng)感知剪貼板的變化,windows提供了兩個(gè)API函數(shù)。使用SetClipBoard可以將窗體注冊(cè)到剪貼板觀測(cè)鏈中,然后程序就能響應(yīng)剪貼板的變化消息。剪貼板觀察器是一個(gè)顯示剪貼板當(dāng)前內(nèi)容的窗口。剪貼板觀察鏈?zhǔn)且幌盗邢嗷オ?dú)立的剪貼板觀察窗口,它們都能夠接受當(dāng)前發(fā)送到剪貼板的內(nèi)容。

    SetClipBoard的原型是:

    function SetClipBoard(hwndNewViewer:HWND):HWND;

    hwndNewViewer為要注冊(cè)的窗體句柄。如果注冊(cè)成功,則返回剪貼板觀測(cè)鏈中下一個(gè)窗體的句柄;如果發(fā)生錯(cuò)誤或無(wú)其他窗體,則返回NULL

    如果剪貼板發(fā)生變化,windows會(huì)向窗體發(fā)送WM_CHANGECCHAINWM_DRAWCLIPBOARD消息,觀測(cè)鏈中每個(gè)窗體都會(huì)調(diào)用SendMessage將該消息傳送給下一個(gè)窗體。當(dāng)應(yīng)用程序退出時(shí),要利用API函數(shù)ChangeClipboardChain將窗體從剪貼板觀測(cè)鏈中移去。其原型為:

    function ChangeClipboardChain(hWndRemove, hWndNewNext:HWND):boolean;

    hWndRemove將要?jiǎng)h除的窗口的句柄, hWndNewNextSetClipBoard返回的窗體的句柄。

    這樣我們只要在程序中等待剪貼板變化的消息即可。當(dāng)消息到來(lái)時(shí),我們應(yīng)該怎樣得到剪貼板中的內(nèi)容呢?Delphiclipbrd.pas單元中定義了一個(gè)類TClipboard,它封裝了Windows剪貼板,簡(jiǎn)化了大量復(fù)雜的處理過(guò)程。我們?cè)诔绦蛑锌梢灾苯诱{(diào)用全局函數(shù)Clipboard,該函數(shù)用于返回TClipboard對(duì)象實(shí)例,使用這個(gè)實(shí)例對(duì)剪貼板進(jìn)行剪切、復(fù)制和粘貼等操作。下面是TClipboard對(duì)象的幾個(gè)常用的方法和屬性的簡(jiǎn)單介紹:

    方法:

    procedure Clear; 清空剪貼板。

    function HasFormat(Format: Word): Boolean; 查詢剪貼板中是否有指定格式的內(nèi)容。可以有三種取值:CF_TEXT(文字)CF_BITMAP(位圖)CF_METAFILEPICT(元文件)

    屬性:

    AsText:用于讀寫(xiě)剪貼板文字內(nèi)容。

     

    如何給用戶保存下來(lái)的圖片文件命名也是個(gè)問(wèn)題。我們可以設(shè)置一個(gè)全局整型變量,每當(dāng)保存一個(gè)圖片文件時(shí),就令這個(gè)變量增加1,將這個(gè)整型變量轉(zhuǎn)換成字符串做為文件名。如果指定的文件名已經(jīng)存在,就要給文件重命名。最簡(jiǎn)單的辦法就是在文件名之前(或之后)加上一個(gè)字符串(比如'new'),如果加上這個(gè)字符串后還是存在重名的文件呢?這就要用到學(xué)編程的人在一開(kāi)始就學(xué)到的一個(gè)小技巧:遞歸。這個(gè)問(wèn)題的解決辦法見(jiàn)下面的代碼:

    procedure SaveToPic(APic: TJPegImage; AFileName: string);

    Const PICPLUSSTR = 'new';

    begin

      if FileExists(AFileName) then

        savetopic(ABmp, PICPLUSSTR+AFileName)

      else

          SaveBmpAsJpg(APic, AFileName);

    end;

     

    在實(shí)際應(yīng)用的時(shí)候,還應(yīng)該加上異常處理(如磁盤(pán)空間已滿,文件名過(guò)長(zhǎng)等)。圖片的保存的基本問(wèn)題已經(jīng)解決,我們?cè)賮?lái)看看文字的保存。為了增強(qiáng)程序的靈活性,我們應(yīng)該使用用戶能方便地將不同地文字保存到不同的文件。繼續(xù)沿用上面保存圖片的方式用數(shù)字做文件名嗎?當(dāng)然不可以。一是因?yàn)槲谋疚募幌駡D片那樣在資源管理器中可以預(yù)覽,用戶必須打開(kāi)文件才能知道文件中保存的是什么內(nèi)容,如果用戶想在一大堆“1.txt”、“2.txt”……中找自己想要的內(nèi)容就太麻煩了;二是因?yàn)橛脩舨⒉灰竺看螐?fù)制下來(lái)的內(nèi)容都保存到單一的文件中,而是要將相關(guān)的內(nèi)容保存到一個(gè)文件中。我對(duì)這個(gè)問(wèn)題的解決方法是這樣的:

    用戶可以先復(fù)制一段文字,然后再按一個(gè)熱鍵(比如Ctrl+Alt+S,為什么要選Ctrl+Alt+S做熱鍵呢?后面再說(shuō)!),這樣用戶以后復(fù)制下的文字就保存到以用戶復(fù)制的文字做為文件名的文件中。

    記得無(wú)數(shù)位大師說(shuō)過(guò):“要將用戶界面與業(yè)務(wù)邏輯分開(kāi)。”好吧,就將上面的東西封裝一下,也算是我向OO邁進(jìn)的第一步吧!(下面之列出了類的部分成員)

      TWebPageSaver = class(TObject)

      private

        FImagePath: string;

        FTextPath: string;

        FImageCount: Integer;

        FTextFileName: string;

        procedure SetImagePath(const Value: string);

        procedure SetTextPath(const Value: string);

      public

        function Save: Boolean;//result is whether the content is saved

        procedure NewTextFile(AFileName:string);

        property ImagePath: string read FImagePath write SetImagePath;

        property TextPath: string read FTextPath write SetTextPath;

      end;

    在用戶界面中,當(dāng)用戶按下熱鍵Ctrl+Alt+S時(shí),就調(diào)用TWebPageSaver.NewTextFile更改文字保存的文件名FTextFileName;當(dāng)收到剪貼板變化的消息時(shí)就調(diào)用TWebPageSaver.Save保存剪貼板中的內(nèi)容。另外還有ImagePathTextPath等屬性,可以由用戶來(lái)更改圖片、文字的保存路徑。

     

    核心代碼已經(jīng)完成,來(lái)做一下用戶界面吧!仿照著“windows優(yōu)化大師”我做了如下的界面:

    ns1.jpg

     

     

     

     

     

     

    很漂亮吧?左邊我用的是TSpeedButton組件,右邊是TNotePage組件。當(dāng)用戶點(diǎn)擊一個(gè)TSpeedButton時(shí),調(diào)用TNotePage.ActivePage := '頁(yè)面的代號(hào)'就可以激活相應(yīng)的配置界面。這個(gè)軟件需要在后臺(tái)運(yùn)行,那么就讓它在平時(shí)縮小到系統(tǒng)托盤(pán)吧!將程序縮小到系統(tǒng)托盤(pán)很容易做到,網(wǎng)上有很多這樣的示例代碼。我手頭有一個(gè)控件cooltray4.3可以用來(lái)實(shí)現(xiàn)系統(tǒng)托盤(pán)的功能,我就懶得自己再去寫(xiě)代碼了。

    軟件運(yùn)行一切良好。不過(guò)一直令我耿耿于懷的就是網(wǎng)上那種防復(fù)制的網(wǎng)頁(yè):不管你怎么拖動(dòng)鼠標(biāo),那些文字就是無(wú)法被選定。仔細(xì)想一想,既然文字能夠在IE上顯示就一定可以得到它們。在MSDN中找了半天,才找到解決方法。可以通過(guò)ShellWindows集合來(lái)代表屬于shell 的當(dāng)前打開(kāi)的窗口的集合,而IE就是屬于shell的一個(gè)應(yīng)用程序。用CoShellWindows.Create得到當(dāng)前打開(kāi)的shell的接口(IShellWindows),調(diào)用接口的Count屬性得到當(dāng)前打開(kāi)的shell的數(shù)量,然后遍歷這些窗口,嘗試從接口中取出IWebbrowser2接口(通過(guò)ShellWindow.Item(I) as IWebbrowser2這樣的接口類型轉(zhuǎn)換方式),如果結(jié)果不為nil說(shuō)明這個(gè)窗口是IE窗口。之后只要調(diào)用IWebBrowser2接口的相應(yīng)方法即可得到窗口中的文字、URL、標(biāo)題等內(nèi)容了。

    示例代碼如下:

    {需要使用mshtml,SHdocvw兩個(gè)單元}  

    var

     ShellWindow : IShellWindows;

     WebBrowser : IWebBrowser2;

     I, ShellWindowCount: integer;

     HTMLdocument : IHTMLdocument2;

     URL, Title, Text:string;

    begin

      ShellWindow := CoShellWindows.Create;

      ShellWindowCount := ShellWindow.Count;

      for I := 0 to ShellWindowCount-1 do

      begin

        WebBrowser := ShellWindow.Item(I) as IWebbrowser2;

        if WebBrowser <> nil then

            begin

                HTMLDocument := WebBrowser.Document as IHtmlDocument2;

                URL := URL;

                Title := HTMLDocument.title;

                Text := HTMLDocument.body.outerText ;

                ShowMessage(URL+Title+Text);

            end;

      end;

      ShellWindow := nil;

    end;

     

    我們定義一個(gè)記錄類型:

      TWebPageRecord = record

        URL: string;  //保存網(wǎng)頁(yè)的URL

        Title: string;//保存網(wǎng)頁(yè)的標(biāo)題

        Text: string; //保存網(wǎng)頁(yè)的文字

      end;

     

    然后定義一個(gè)TWebPageRecord類型的數(shù)組FWebPageRecordArray,大小定位20吧(我想一般人不會(huì)打開(kāi)20個(gè)以上的IE吧):

    Const  MAXPAGECOUNT = 20;

    ……

    FWebPageRecordArray : array [0..MAXPAGECOUNT-1] of TWebPageRecord;

    在遍歷IE窗口時(shí),向數(shù)組中的元素的相應(yīng)字段復(fù)制即可。

    對(duì)這個(gè)復(fù)制防復(fù)制(好拗口呀:))網(wǎng)頁(yè)的功能也封裝成一個(gè)類吧!

    type

      TWebCracker = class(TObject)

      private

        FWebPageRecordArray : array [0..MAXPAGECOUNT-1] of TWebPageRecord;

        FWebPageCount: Integer;

      public

        procedure SnapShot;

        function GetWebText(AIndex:integer): string;

        function GetWebTitle(AIndex:integer): string;

        function GetWebURL(AIndex:integer): string;

        procedure Clear;

        procedure Refresh;

        function GetWebPageCount: Integer;

      end;

    在用戶界面中,可以通過(guò)調(diào)用TWebCracker.SnapShot;來(lái)對(duì)打開(kāi)的IE窗口進(jìn)行遍歷,并保存到FWebPageRecordArray這個(gè)數(shù)組中。通過(guò)TWebCracker.GetWebPageCount方法可以得到FWebPageRecordArray中保存的頁(yè)面的個(gè)數(shù),通過(guò)GetWebTextGetWebTitleGetWebURL就可以得到指定頁(yè)面的文字、標(biāo)題或是URL

    一切都已經(jīng)搞定了!爽!

     

    通過(guò)編寫(xiě)這個(gè)小軟件,我是收獲頗豐呀!除了學(xué)到了上邊這些技巧外,我還有一些小的經(jīng)驗(yàn),愿意與大家分享:

    1、為用戶著想,讓用戶舒服

    用戶是上帝嘛!以那個(gè)Ctrl+Alt+S熱鍵來(lái)說(shuō)吧:一般用戶上網(wǎng)都是右手握鼠標(biāo),空下來(lái)的只有左手。小拇指按Ctrl,大拇指按Alt,食指剛好能按到S鍵,不費(fèi)一點(diǎn)力氣!

    2 良好的編碼習(xí)慣

    1)不要出現(xiàn)魔術(shù)數(shù)

    TWebCracker定義的那個(gè)FWebPageRecordArray數(shù)組來(lái)說(shuō):

    Const  MAXPAGECOUNT = 20;

    ……

    FWebPageRecordArray : array [0..MAXPAGECOUNT-1] of TWebPageRecord;

    別人一看MAXPAGECOUNT就知道是什么意思,而如果你寫(xiě)成:

    FWebPageRecordArray : array [0..19] of TWebPageRecord;

    估計(jì)除了你自己沒(méi)有人能夠知道19到底是什么意思。

    2)用sender的方式增強(qiáng)代碼的健壯性

    procedure TMainfrm.CBAutoRunClick(Sender: TObject);

    Const

      SIGNINREGISTRY = 'WebSuction';

    begin

      if (Sender as TCheckBox).Checked then 

         AddToAutoRun(Application.ExeName,SIGNINREGISTRY)

      else DelAutoRun(SIGNINREGISTRY);

    end;

    這樣即使Checkbox1改了名字也不怕。

    又如:

    procedure TMainfrm.N1Click(Sender: TObject);

    begin

      if (Sender as TMenuItem).Caption = '暫停(&S)' then

        begin

          (Sender as TMenuItem).Caption := '開(kāi)始(&R)';

          FWebPageSaver.Pause;

        end

      else

        begin

          (Sender as TMenuItem).Caption := '暫停(&S)';

          FWebPageSaver.ReStart;

        end;

    end;

    3)不要直接使用Tform2單元的全局Form2變量,那樣就破壞了封裝性

    procedure TMainfrm.SBNextClick(Sender: TObject);

    var

      LSelectedIndex : integer;

      FormDisplay : Tform2;

    begin

      LSelectedIndex := LBWebPage.ItemIndex;

      if LSelectedIndex <> -1 then

      begin

        FormDisplay := Tform2.Create(self);

        FormDisplay.SetContent(FWebCracker.GetWebText(LSelectedIndex));

        FormDisplay.Show;

      end;

    end;

    TForm2中定義 SetContent方法

    procedure TWebCrackfrm.SetContent(AText:string);

    begin

      Memo.Clear;

      Memo.Lines.Add(AText);

    end;

    posted on 2005-10-22 00:45 CowNew開(kāi)源團(tuán)隊(duì) 閱讀(468) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲国产日韩女人aaaaaa毛片在线| 国产亚洲精品免费| 99re6在线精品视频免费播放| 最近免费字幕中文大全| 国产一区二区三区免费观看在线| 国产乱妇高清无乱码免费| 精品国产呦系列在线观看免费| 岛国岛国免费V片在线观看 | 久久久久亚洲Av无码专| 婷婷亚洲久悠悠色悠在线播放| 午夜亚洲AV日韩AV无码大全| 亚洲精品中文字幕无码AV| 亚洲图片激情小说| 亚洲精品又粗又大又爽A片| WWW亚洲色大成网络.COM | 久久亚洲日韩看片无码| 亚洲国产成人精品电影| 亚洲私人无码综合久久网| 亚洲欧美日韩中文字幕一区二区三区 | 亚洲国产夜色在线观看| 亚洲日韩久久综合中文字幕| 免费在线观看自拍性爱视频| 久久久久久噜噜精品免费直播 | a毛片免费全部在线播放**| 日韩精品极品视频在线观看免费| 中文字幕视频免费| 成人午夜免费福利| 亚洲成A人片在线观看中文| 在线亚洲午夜理论AV大片| 亚洲一区二区三区四区在线观看| 亚洲图片中文字幕| 特黄特色大片免费| 3344在线看片免费| 免费A级毛片无码免费视| 亚洲AV无码乱码在线观看| 久久精品亚洲一区二区| 最新国产成人亚洲精品影院| 日韩在线一区二区三区免费视频| 男人天堂免费视频| 日韩精品成人无码专区免费| 亚洲精品无码日韩国产不卡?V|