<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開源團(tuán)隊(duì)

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

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

    凌科網(wǎng)頁精靈開發(fā)手記

    楊中科

    現(xiàn)在網(wǎng)上有大量的網(wǎng)頁特效軟件供網(wǎng)頁制作者使用,但是大多數(shù)網(wǎng)頁特效軟件只是羅列了如果將網(wǎng)頁特效代碼添加到html文檔中,比如:

    第一步:把如下代碼加入<body>區(qū)域中:

      <span id=liveclock style=position:absolute;left:250px;top:122px>

    </span>    (這里可以調(diào)整時(shí)鐘的方位。調(diào)用腳本時(shí)去掉括號中內(nèi)容)

    <SCRIPT language=javascript>

    var minutes=Digital.getMinutes()

    if(hours>12){dn="PM"

    hours=hours-12

    }

    ……………………

    setTimeout("show5()",1000)

    }

    </SCRIPT>

    第二步:<body>中的內(nèi)容改為

    <body bgcolor="#fef4d9" ONLOAD=show5()>

     

    這要求網(wǎng)頁制作者必須了解html語言,而且即使對熟悉html的用戶要想修改特效代碼中的參數(shù)(比如上面例子中的“調(diào)整時(shí)鐘的方位”)也是非常麻煩。這款軟件則解決了這個(gè)問題,您只要選擇一個(gè)要添加的特效,在彈出的對話框中填入幾個(gè)相關(guān)參數(shù),軟件將自動將特效代碼添加到網(wǎng)頁代碼的合適位置。

    比如給軟件添加一個(gè)旋轉(zhuǎn)立體字的特效,只要選擇“插件”->“旋轉(zhuǎn)立體字”,就會彈出下面的對話框:

    pages1.jpg

    在對話框中填入各個(gè)參數(shù)后,網(wǎng)頁精靈就自動幫您把代碼插入到正確的位置了。

    這款軟件的技術(shù)核心就是插件化開發(fā)和程序自動升級技術(shù)。下面我將分別講解這兩項(xiàng)技術(shù)在“網(wǎng)頁精靈”的應(yīng)用。

    一、插件化開發(fā)。

    1、基本原理

         凌科網(wǎng)頁精靈中每個(gè)插件都是一個(gè)dll文件。插件這個(gè)名詞大家都很熟悉。如PhotoShop等軟件就是通過安裝很多插件來實(shí)現(xiàn)某些特殊功能的。插件僅僅是從外部提供給應(yīng)用程序的一個(gè)接口,通過調(diào)用約定的接口來實(shí)現(xiàn)插件所提供的功能。使用插件化開發(fā)的好處是明顯的,它可以很輕松的實(shí)現(xiàn)軟件的擴(kuò)展,并且簡化的軟件設(shè)計(jì)的構(gòu)架,使得開發(fā)程序變得更加簡單。

    插件化開發(fā)可以通過很多技術(shù)實(shí)現(xiàn),比如COM,Dll等。我們這里采用Dll文件的形式實(shí)現(xiàn)插件。基本思想如下:程序每次啟動時(shí),在指定的目錄下查找*.dll文件,然后將其加入到某個(gè)菜單下。在用戶點(diǎn)擊插件對應(yīng)的菜單項(xiàng)時(shí),只要調(diào)用接口函數(shù)中約定好的某個(gè)函數(shù)就可以。

    2、插件導(dǎo)出的接口

    凌科網(wǎng)頁精靈中每個(gè)插件都必須導(dǎo)出下面三個(gè)接口函數(shù):

    GetPlugInHTML, GetPlugInName, GetPlugInDescription;

    它們的函數(shù)原型的pascal描述如下

      function GetPlugInHTML(AHandle: THandle;ASelectedText: PChar;

                       AResultHTHML: TResultHTML): Boolean;stdcall;

      procedure GetPlugInName(AValue: PChar);stdcall;

      procedure GetPlugInDescription(AValue: PChar);stdcall;

    其中 TResultHTMLpascal定義如下

    TResultHTML = record

        ReplaceHTML: PChar; //替換文字

        BodyHTML: PChar;//添加到<Body></Body>區(qū)的文字

        BodyTagHTML: PChar;//添加到<Body >中的文字,如<Body onload="show()">

        HeadHTML: PChar;//添加到<Head></Head>區(qū)中的文字

      end;

    接口函數(shù)描述:

    1  function GetPlugInHTML(AHandle: THandle;ASelectedText: PChar;

                       AResultHTHML: TResultHTML): Boolean;stdcall;

    在用戶點(diǎn)擊插件對應(yīng)的菜單時(shí),主程序?qū)⒄{(diào)用此方法來得到插件返回的對網(wǎng)頁的修改信息。

    其中AHandle對應(yīng)主窗口,也就是網(wǎng)頁精靈的窗體句柄;ASelectedText代表用戶此時(shí)在網(wǎng)頁編輯器中選中的文本;AResultHTHML是返回值,將用ReplaceHTML將替換用戶選擇的文本,將把BodyHTML添加到網(wǎng)頁的<Body></Body>區(qū),將把BodyTagHTML添加到<Body >,如在未調(diào)用插件的時(shí)候<Body> 在調(diào)用后bodyTagHTML=‘onload="show()"’則調(diào)用后<Body onload="show()">,將HeadHTML添加到<Head></Head>區(qū);

    返回值代表此插件的運(yùn)行是否成功。如果返回False,則主程序會忽略插件對網(wǎng)頁的修改信息。

    2procedure GetPlugInName(AValue: PChar);stdcall;返回值是AValue,它將做為菜單的標(biāo)題,代表插件的名稱。

    3void GetPlugInDescription(char* AValue);返回值是AValue,它將做為此插件的功能描述。

    3、動態(tài)加載插件

    加載插件信息到菜單的偽代碼如下(關(guān)于FindFirst,FindNext的使用請參考Delphi的幫助, LoadLibrary, GetProcAddress, FreeLibrary的使用請參考MSDN):

    var

      LGetPlugInName: TGetPlugInName;

      LSr: TSearchRec;

      LHandle: THandle;

      LName: PChar;

    begin

      FPlugIns.Clear;

      if FindFirst(Adir+‘*.dll’, faAnyFile - faDirectory,LSr) = 0 then

    // Adir是插件所在路徑

        repeat

          LHandle := LoadLibrary(PChar(ADir + LSr.Name));

          try

            GetMem(LName, MAXNAMEDESCSIZE);

            @LGetPlugInName := GetProcAddress(LHandle, 'GetPlugInName');

          //調(diào)用GetPlugInName到插件的名稱

            LGetPlugInName(LName);

            增加一個(gè)菜單,并設(shè)定菜單的標(biāo)題為Lname;

    設(shè)定菜單的OnClick事件句柄=OnPlugInClick;

    // OnPlugInClick的定義在后邊

    將插件的文件名與菜單通過一定方法聯(lián)系起來;

    //聯(lián)系起來以供在點(diǎn)擊菜單的時(shí)候加載此插件

          finally

            FreeLibrary(LHandle);

            FreeMem(LName);

           end;

     

        until (FindNext(LSr) <> 0);

    end;

     

    其中

      TGetPlugInName = procedure(AValue: PChar);stdcall;

     

    4、運(yùn)行插件

    在用戶點(diǎn)擊菜單之后將觸發(fā)我們在上邊設(shè)定的OnPlugInClick事件句柄。

    procedure TFormMain.OnPlugInClick(Sender: TObject);

    var

      LHandle: THandle;

      LGetPlugInHTML: TGetPlugInHTML;

      LPlugInInfo: TPlugInInfo;

      LRH: TResultHTML;

    begin

      LHandle := LoadLibrary(PChar(FPlugInsDir + LPlugInInfo.FileName));

      try

        @LGetPlugInHTML := GetProcAddress(LHandle, 'GetPlugInHTML');

        LTmpStr := Trim(RichEditHTML.SelText);

        GetMem(LRH.ReplaceHTML, MAXHTMLSIZE);

        GetMem(LRH.BodyHTML, MAXHTMLSIZE);

        GetMem(LRH.BodyTagHTML, MAXHTMLSIZE);

    GetMem(LRH.HeadHTML, MAXHTMLSIZE);

     

    //調(diào)用DLL中的GetPlugInHTML

        LGetPlugInHTML(self.Handle, PAnsiChar(LTmpStr),LRH);

        根據(jù) LRH中的信息更改HTML頁面中的相應(yīng)區(qū)域;

      finally

         釋放資源;

      end;

    5、開發(fā)插件示例

    下面以開發(fā)一個(gè)“添加到收藏夾”插件為例來展示一下插件的開發(fā)。

    實(shí)現(xiàn)這個(gè)功能的HTML如下:

    <a href="javascript:window.external.AddFavorite('http://www.sohu.com', '搜狐

    網(wǎng)')">將本站加入收藏夾</a>

    顯然我們可以提供三個(gè)參數(shù)供用戶選擇,那就是網(wǎng)址(如http://www.sohu.com)、網(wǎng)站名稱(如 “搜狐網(wǎng)”)、超鏈接的標(biāo)題(如“將本站加入收藏夾”)。

    新建一個(gè)Dll工程,在工程文件中導(dǎo)出Dll輸出的函數(shù)

    exports

      GetPlugInHTML, GetPlugInName, GetPlugInDescription;

    新建一個(gè)窗體,布局如下:

    pages2.jpg

    將一個(gè)TbigStringContainer控件(我開發(fā)的可以存儲大字符串的控件,在開發(fā)包中),放到窗體中,雙擊strings屬性,輸入一下的文本:

    <a href="javascript:window.external.AddFavorite('<!url>', '<!favoritename>')"><!text></a>

    其中“'<!url>”、“<!favoritename>”、“<!text>”是我們要根據(jù)用戶輸入的值替換的字符串。

    在窗體的public中定義如下的方法:

    function GetReplaceHTML: string;

    代碼如下

    var

      t: string;

    begin

      t := bigStringContainer1.GetString;

      t := AnsiReplaceStr(t, '<!url>', EdtUrl.Text);

     //t字符串中的<!url>, EdtUrl.Text替換

      t := AnsiReplaceStr(t, '<!favoritename>', EdtFaName.Text);

      t := AnsiReplaceStr(t, '<!text>', EdtText.Text);

      result := t;

    end;

    Dll導(dǎo)出的三個(gè)函數(shù)的主要代碼如下:

    function GetPlugInHTML(AHandle: THandle;ASelectedText: PChar;

                       AResultHTHML: TResultHTML): Boolean;stdcall;

    var

      Dlg: TFormFavorite;

    begin

      result := false;

      AResultHTHML.ReplaceHTML[0] := #0;

      AResultHTHML.BodyHTML[0] := #0;

      AResultHTHML.BodyTagHTML[0] := #0;

      AResultHTHML.HeadHTML[0] := #0;

     

      if ASelectedText <> nil then

        StrLCopy(AResultHTHML.ReplaceHTML, ASelectedText, MAXHTMLSIZE);

     

      Dlg := TFormFavorite.Create(nil);

      Dlg.ParentWindow := AHandle;

      if Dlg.ShowModal = mrOK then

      begin

        result := true;

        FillMemory(AResultHTHML.ReplaceHTML, MAXHTMLSIZE, 0);

    StrLCopy(AResultHTHML.ReplaceHTML, PChar(Dlg.GetReplaceHTML),MAXHTMLSIZE);

      end;

    Dlg.free;

    end;

     

    procedure GetPlugInName(AValue: PChar);stdcall;

    begin

      FillMemory(AValue, MAXNAMEDESCSIZE, 0);

      StrLCopy(AValue, PChar('添加到收藏夾功能'), MAXNAMEDESCSIZE);

    end;

     

    procedure GetPlugInDescription(AValue: PChar);stdcall;

    begin

      FillMemory(AValue, MAXNAMEDESCSIZE, 0);

      StrLCopy(AValue, PChar('本插件將為在網(wǎng)頁中添加到收藏夾功能'),MAXNAMEDESCSIZE);

    end;

    編譯后將插件放到“網(wǎng)頁精靈”的插件目錄下,啟動“網(wǎng)頁精靈”就可以看到這個(gè)插件已經(jīng)被加載到了菜單中。

    二、軟件自動升級技術(shù)

    當(dāng)我們開發(fā)了新插件后,肯定希望用戶能盡快得到此插件。應(yīng)用程序升級的方法有兩種:一是通知用戶讓用戶到指定網(wǎng)站下載插件,然后由用戶將插件放到插件目錄下面;二是由程序負(fù)責(zé)從服務(wù)器上下載安裝插件,用戶唯一要做的就是決定是否愿意安裝新插件。顯然后一種方法比較好。

    1、基本原理

    在本地有一個(gè)存儲已安裝插件的信息的列表,在服務(wù)器端也維護(hù)一個(gè)服務(wù)器上的所有插件信息的列表。當(dāng)要升級插件的時(shí)候,程序從服務(wù)器上下載此列表,與本地的列表比較,如果發(fā)現(xiàn)本地沒有的插件,就將此插件下載下來,安裝到插件目錄下即可。

    2、列表的結(jié)構(gòu)

    由于列表中要保存所有插件的文件名、名稱、版本、描述等信息,所以用XML文件來保存比較合適。我定義XML文檔格式如下:

    <PlugInsList>

      <PlugIn>

        <FileName>插件的文件名</FileName>

        <Name>插件的名稱</Name>

        <Version>版本</Version>

        <Description>插件描述</Description>

    </PlugInsList>

    3、定義XML文件映射

    我們可以使用DOMSAX等解析XML文檔,但是寫起來很麻煩。好在咱們偉大的女神Delphi為我們提供了XML Data Binding Wizard這個(gè)強(qiáng)大的工具。XML數(shù)據(jù)綁定向?qū)?/SPAN>(XML Data Binding Wizard)可以將XML文件映射成類,這樣程序員能夠用它生成相應(yīng)的接口和類來訪問與修改XML文件數(shù)據(jù),完全沒有陌生感,用起來就好像使用普通的類一樣。

     

    運(yùn)行Delphi7,點(diǎn)擊“File->”O(jiān)ther”,選擇“New”頁面中的“XML Data Binding Wizard”。用記事本建立如下文件:

    <PlugInsList>

      <PlugIn>

        <FileName>文件名</FileName>

        <Name>名稱</Name>

        <Version>版本</Version>

    <Description>插件描述</Description>

      </PlugIn>

      <PlugIn>

        <FileName>插件的文件名</FileName>

        <Name>插件的名稱</Name>

        <Version>版本</Version>

        <Description>插件描述</Description>

      </PlugIn>

    </PlugInsList>

    注意:

      <PlugIn></PlugIn>必須要寫多于兩組(包含兩組),否則向?qū)J(rèn)為<PlugIn></PlugIn>是只能有一組的元素,從而生成的映射類無法供我們使用。而寫成多于兩組的時(shí)候向?qū)?/SPAN><PlugIn>屬性映射成<PlugInsList>的一個(gè)數(shù)組屬性。

    以下是生成的代碼的接口部分:

      IXMLPlugInsListType = interface;

      IXMLPlugInType = interface;

     

    { IXMLPlugInsListType }

     

      IXMLPlugInsListType = interface(IXMLNodeCollection)

        ['{5D777B2B-E265-472B-8035-ADCED92E0F65}']

        { Property Accessors }

        function Get_PlugIn(Index: Integer): IXMLPlugInType;

        { Methods & Properties }

        function Add: IXMLPlugInType;

        function Insert(const Index: Integer): IXMLPlugInType;

        property PlugIn[Index: Integer]: IXMLPlugInType read Get_PlugIn; default;

      end;

     

    { IXMLPlugInType }

     

      IXMLPlugInType = interface(IXMLNode)

        ['{76ED7F51-20FF-4A4A-87B7-CFB9BB280F80}']

        { Property Accessors }

        function Get_FileName: WideString;

        function Get_Name: WideString;

        function Get_Version: WideString;

        function Get_Description: WideString;

        procedure Set_FileName(Value: WideString);

        procedure Set_Name(Value: WideString);

        procedure Set_Version(Value: WideString);

        procedure Set_Description(Value: WideString);

        { Methods & Properties }

        property FileName: WideString read Get_FileName write Set_FileName;

        property Name: WideString read Get_Name write Set_Name;

        property Version: WideString read Get_Version write Set_Version;

        property Description: WideString read Get_Description write Set_Description;

      end;

     

    { Forward Decls }

     

      TXMLPlugInsListType = class;

      TXMLPlugInType = class;

     

    { TXMLPlugInsListType }

     

      TXMLPlugInsListType = class(TXMLNodeCollection, IXMLPlugInsListType)

      protected

        { IXMLPlugInsListType }

        function Get_PlugIn(Index: Integer): IXMLPlugInType;

        function Add: IXMLPlugInType;

        function Insert(const Index: Integer): IXMLPlugInType;

      public

        procedure AfterConstruction; override;

      end;

     

    { TXMLPlugInType }

     

      TXMLPlugInType = class(TXMLNode, IXMLPlugInType)

      protected

        { IXMLPlugInType }

        function Get_FileName: WideString;

        function Get_Name: WideString;

        function Get_Version: WideString;

        function Get_Description: WideString;

        procedure Set_FileName(Value: WideString);

        procedure Set_Name(Value: WideString);

        procedure Set_Version(Value: WideString);

        procedure Set_Description(Value: WideString);

      end;

     

    { Global Functions }

     

    function GetPlugInsList(Doc: IXMLDocument): IXMLPlugInsListType;

    function LoadPlugInsList(const FileName: WideString): IXMLPlugInsListType;

    function NewPlugInsList: IXMLPlugInsListType;

     

    我們直接使用的兩個(gè)接口是:

     

      IXMLPlugInsListType = interface(IXMLNodeCollection)

     

      IXMLPlugInType = interface(IXMLNode)

    向?qū)н€提供了三個(gè)全局方法可以簡化我們的操作:

    function GetPlugInsList(Doc: IXMLDocument): IXMLPlugInsListType;

    function LoadPlugInsList(const FileName: WideString): IXMLPlugInsListType;

    function NewPlugInsList: IXMLPlugInsListType;

    1)、我們一般將一個(gè)TXMLDocument組件(實(shí)現(xiàn)了IXMLNode接口)做為GetPlugInsList的參數(shù),GetPlugInsList將返回這個(gè)TXMLDocument組件對應(yīng)的XML文檔的根元素。

    2)、也可以將XML文件的文件名傳遞給function LoadPlugInsList(const FileName: WideString): IXMLPlugInsListType;返回值同樣是對應(yīng)的XML文檔的根元素。

    3)、function NewPlugInsList: IXMLPlugInsListType;

    在內(nèi)存生成新文件。我們這里不直接用到它。

    我們可以用IXMLPlugInsListType操縱文件中的<PlugInsList>中的<PlugIn>列表。

      function Get_PlugIn(Index: Integer): IXMLPlugInType;

      返回列表中指定位置Index的節(jié)點(diǎn)。

     function Add: IXMLPlugInType;

    將在列表中的最后位置添加一個(gè)節(jié)點(diǎn),返回剛添加的節(jié)點(diǎn)。

    function Insert(const Index: Integer): IXMLPlugInType;

    將在列表中的Index后位置添加一個(gè)節(jié)點(diǎn),返回剛添加的節(jié)點(diǎn)。

    property PlugIn[Index: Integer]: IXMLPlugInType read Get_PlugIn;

    則是一個(gè)以數(shù)組方式展現(xiàn)的所有節(jié)點(diǎn)的列表。

    IXMLPlugInType的所有屬性FileNameVersion等,都是對<PlugIn>的屬性的映射。

    4、XML文件的讀寫操作

     以前在Delphi中想操作XML文檔要頻繁調(diào)用XML API,十分的煩人。現(xiàn)在 XML Data Binding Wizard加上TXMLDocument(Internet面板上)簡化了我們的操作。雙劍合壁,誰與爭風(fēng)!

    XML中添加新的節(jié)點(diǎn)的方法如下:

    1var

      ALocalList: IXMLPlugInsListType;

      ALocalNode: IXMLPlugInType;

      begin

     

              ALocalList := GetPlugInsList(XMLDocLocal);

    // XMLDocLocalTXMLDocument控件

        ALocalNode := ALocalList.Add;

        ALocalNode.FileName := ‘DllFilename’;

        ALocalNode.Name := ‘name’;

        ALocalNode.Version := ‘version’;

        ALocalNode.Description := ‘description’

    XMLDocLocal.SaveToFile();

    //如果XMLDocLocalAutoSave=True則不用SaveToFile;

    End;

    (2)讀取一個(gè)節(jié)點(diǎn)的方法可以參考添加節(jié)點(diǎn)的代碼。

    5、自動升級

    有了上邊的知識相信開發(fā)一個(gè)自動升級的系統(tǒng)已經(jīng)不難了,您可以參考源代碼自己分析,我就不多費(fèi)口舌了。忘了說一點(diǎn),從服務(wù)器上下載XML列表可以使用WinInetIdHTTP控件,我用的就是IdHTTP控件(方便呀,調(diào)用一個(gè)Get方法就可以做到,還支持代理服務(wù)器!嘻嘻!)。得到列表后賦值給TXMLDocumentXML.Text屬性就可以。

    pages3.jpg

    pages4.jpg

    三、其他經(jīng)驗(yàn)總結(jié)

    1、預(yù)覽功能的實(shí)現(xiàn)

    預(yù)覽功能可以使用WebBrowser控件,在切換到“預(yù)覽”頁面的時(shí)候,將HTML代碼保存到文件中,然后調(diào)用WebBrowser.Navigate()方法將此頁面加載即可。

    但是這里有一個(gè)如果保存網(wǎng)頁文件的問題,如果指定一個(gè)文件名,如”tmp.htm”,這樣在程序打開一個(gè)的時(shí)候沒問題,如果打開多個(gè)程序就會造成混亂:一個(gè)程序保存的”tmp.htm”被另一個(gè)程序加載了,會令人感到莫名其妙。

    我解決此問題的方法是使用程序的句柄做為文件名。Windows每個(gè)程序都有一個(gè)句柄,即使是同一個(gè)軟件的兩個(gè)實(shí)例它們的句柄也不同。這個(gè)句柄本質(zhì)上是一個(gè)整形數(shù),所以可以把它轉(zhuǎn)換成一個(gè)字符串做為文件名,在程序退出時(shí)刪除此文件(如果保存在系統(tǒng)臨時(shí)文件夾下就不用刪除,Windows會自動替您刪除)。代碼如下:

    FileName := 'tmp'+IntToStr(Integer(Application.Handle))+'.htm';

    2、“撤銷”功能的實(shí)現(xiàn)

    很多文本編輯器、網(wǎng)頁編輯器都有“撤銷”功能,這樣在用戶想返回編輯前的某個(gè)狀態(tài)時(shí)就會非常方便。我在這里用一個(gè)特殊的“堆棧”解決了這個(gè)問題(數(shù)據(jù)結(jié)構(gòu)還是很管用的呀,一定要好好學(xué)呀)。

    這個(gè)堆棧的特殊之處就在于這個(gè)堆棧有個(gè)最大的容量(也就等于允許最大的撤銷次數(shù),如果不限制最大的撤銷次數(shù)就會導(dǎo)致系統(tǒng)資源越來越少,最后很可能就崩潰了),最特殊的地方就是當(dāng)堆棧增加到滿的后再壓入新元素的時(shí)候就刪除棧底元素,所有上邊的元素都自動下移一個(gè)位置,新壓入的元素放在棧頂。

    我們當(dāng)然可以使用動態(tài)數(shù)組或鏈表解決這個(gè)問題,但是我發(fā)現(xiàn)Contnrs單元中有一個(gè)TobjectList類非常好用,我就用這個(gè)類來實(shí)現(xiàn)這個(gè)堆棧吧!代碼如下:

      //字符串的Wrapper

      TStringObject = class

      public

        Value: string;

      end;

     

      TUndoStack = class(TObject)

      private

        FList: TObjectList;

        FMaxSize: Integer;

      protected

        procedure DelBottom;virtual;//刪除底端一個(gè)

        function FGetCurSize: Integer;

      public

        constructor Create(ASize: Integer);overload;virtual;

        constructor Create;overload;virtual;

        destructor Destroy;override;

        procedure Push(AObj: string);virtual;

        function Pop: string;virtual;

        function IsFull: Boolean;virtual;//是否滿

        function IsEmpty: Boolean;virtual;//是否空

        procedure ClearStack;virtual;//清空

        property MaxSize: Integer read FMaxSize; //最大容量

        property CurSize: Integer read FGetCurSize;//現(xiàn)在的堆棧中的數(shù)量

      end;

     

    constructor TUndoStack.Create(ASize: Integer);

    begin

      inherited Create;

      FList := TObjectList.Create;

      FList.Capacity := ASize;

      FMaxSize := ASize;

      FList.Count := 0;

    end;

     

    constructor TUndoStack.Create;

    begin

      inherited;

      Create(10);//default size

    end;

     

    procedure TUndoStack.DelBottom;

    begin

      if CurSize <= 0 then

        raise Exception.Create('Stack already empty!');

      FList.Delete(0);

      FList.Capacity := FList.Capacity - 1;

      FList.Capacity := FList.Capacity + 1;

    end;

     

    destructor TUndoStack.Destroy;

    begin

      FList.Free;

      inherited;

    end;

     

    function TUndoStack.IsEmpty: Boolean;

    begin

      result := (CurSize <= 0);

    end;

     

    function TUndoStack.IsFull: Boolean;

    begin

      result := (CurSize = MaxSize);

    end;

     

    function TUndoStack.Pop: string;

    begin

      result := '';

      if IsEmpty then

        raise Exception.Create('Stack already Empty!')

      else

      begin

        result := TStringObject(FList.Last).Value;

        FList.Delete(CurSize - 1);

        FList.Capacity := FList.Capacity - 1;

        FList.Capacity := FList.Capacity + 1;

      end;

    end;

     

    procedure TUndoStack.Push(AObj: string);

    var

      a: TStringObject;

    begin

      if IsFull then

      begin

        DelBottom;

      end;

      a := TStringObject.Create;

      a.Value := AObj;

      FList.Add(a);

    end;

     

    procedure TUndoStack.ClearStack;

    begin

      FList.Clear;

    end;

     

    function TUndoStack.FGetCurSize: Integer;

    begin

      FList.Pack;

      result := FList.Count;

    end;

    使用方法如下:

    定義一個(gè)FUndoStack: TUndoStack;撤銷堆棧變量,在用戶對文本做一個(gè)修改動作后調(diào)用

    FUndoStack.Push(RichEditHTML.Lines.Text);

    原來的文本壓入撤銷堆棧 

    在用戶點(diǎn)擊“撤銷”后,調(diào)用

    RichEditHTML.Lines.Text := FUndoStack.Pop;

    來還原到保存的值。

     

     

    posted on 2005-10-22 00:50 CowNew開源團(tuán)隊(duì) 閱讀(715) 評論(0)  編輯  收藏

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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 999zyz**站免费毛片| 亚洲毛片免费视频| 国产又大又粗又长免费视频| 免费无码又爽又刺激毛片| 国产成人精品亚洲精品| 亚洲成在人线电影天堂色| 特黄特色大片免费| 国产免费无码一区二区 | 婷婷国产偷v国产偷v亚洲| 久久免费观看视频| 日本h在线精品免费观看| 国产伦一区二区三区免费 | 亚洲无码精品浪潮| 亚洲经典在线观看| 美女裸免费观看网站| 十八禁无码免费网站| 永久黄网站色视频免费| 亚洲精品无码成人AAA片| 精品亚洲AV无码一区二区三区 | 69影院毛片免费观看视频在线| 日本免费v片一二三区| 亚洲av日韩av不卡在线观看 | 黄页网址在线免费观看| 91香蕉国产线观看免费全集| 国产yw855.c免费视频| 亚洲情a成黄在线观看动漫尤物| 亚洲а∨精品天堂在线| 无码国产精品一区二区免费3p | 亚洲国产成人久久综合野外| 亚洲大片免费观看| 亚欧乱色国产精品免费视频| 97在线线免费观看视频在线观看| 相泽亚洲一区中文字幕| 亚洲中文字幕久久精品无码A| 日韩电影免费在线观看网站| 国产婷婷高清在线观看免费| 亚洲成综合人影院在院播放| 99精品全国免费观看视频..| 国产美女精品视频免费观看| 亚洲欧洲国产视频| 久久久久久久99精品免费观看|