天天看點

“動态文章釋出系統”開發手記

現在網上有很多提供首頁空間的站點,但是大部分低價位的站點隻提供靜态HTML文檔的功能,不支援ASP、PHP等動态網頁技術。如果您像在您的首頁上放上您喜歡的文章,那麼需要一個一個連結的做。如果您删除了某篇文章或者想添加某篇文章,那麼需要做很多改動,牽一發而動全身。

  淩科文章動态釋出系統就是為你解決這個問題而開發的軟體。使用本軟體後您可以輕易生成下面效果的網頁。

///////////////////////////////////

Delphi的使用幫助檔案

最後一篇情書

上一頁

//////////////////////////////////

淩科文章動态釋出預覽

淩科文章動态新技術發

下一頁

/////////////////////////////////

點選相應的文章标題(如"最後一篇情書 ")就會彈出一個視窗顯示這篇文章。

軟體的界面如下:

“動态文章釋出系統”開發手記

這款軟體有兩項關鍵性技術:瘦用戶端的資料庫應用和網頁分頁顯示技術。其中的瘦用戶端的資料庫應用在我的另一款軟體《淩科網頁精靈》的“程式自動更新”功能中也有所應用。

一、瘦用戶端的資料庫應用

本軟體的一個基本要求就是使用者可是随時在工程添加、删除文章,并能将工程儲存到檔案中,并可以在以後打開工程檔案後繼續編輯工程。實作這個功能可以有很多中解決方案:

(1)  定義一個結構體TariticleItem(因為要将文章儲存到ListBox的Item屬性中,是以要用類來模拟結構體):

TariticleItem = class

Public

  Title: string;

  Ariticle: string;

End;

将使用者輸入的标題和文章正文存儲在一個TariticleItem,然後再調用ListBox.Item.Add()将此TariticleItem儲存到ListBox 中,在儲存工程的時候周遊ListBox中每個項目然後儲存到檔案。在加載工程檔案時也類似的周遊項目。

但是這樣會使工作量變得很大,況且很有可能出現記憶體問題(我猜測的,沒有實踐),而且儲存的工程檔案格式也會很難确定。

(2)用Access的MDB資料庫存儲文章,通過ADO操作資料庫。之是以選擇ADO通路Access資料庫而不使用BDE的原因就是BDE的配置十分麻煩,在這種小規模的程式中使用BDE有點恐怖。而Access的ADO驅動在Win98以上作業系統中一般都有安裝,這樣就免去了配置的麻煩。而且使用TADOTable或TADOQuery的SaveToFile和LoadFromFile方法也可以輕易實作資料導出/導入檔案。但是為什麼我們不使用它呢?因為“Win98以上作業系統” “一般”都有安裝,這就說明Win95的使用者就不能使用本軟體了(現在還是有很多Win95使用者的),而且即使是Win98以上的系統也不能保證一定裝有ADO驅動。

(3)使用Delphi中的TclientDataSet 控件。TClientDataSet控件繼承自TDataSet,具有所有資料集元件的基本功能,而且還有自己的很多很有用的功能,它是一款基于檔案型資料存儲和操作的控件,資料可以導出到檔案中(支援xml、cds兩種檔案格式)。該控件封裝了對資料進行操作處理的接口和功能,具有ADO的上述優點,基本上能滿足單機"瘦"資料庫應用程式的需要。Delphi5的使用者在釋出軟體時隻要同時釋出Midas.dll就可以了,Delphi6、Delphi7的使用者隻要在工程檔案中包含MidasLib單元,Midas.dll的功能就內建在應用程式中了(會使程式增大200K左右),成為真正的零配置軟體。況且使用TclientDataSet控件,我們就可以使用資料敏感元件,我們又免去了處理将保持使用者輸入資料更新的問題。基于以上原因,我決定使用TclientDataSet控件。

“動态文章釋出系統”開發手記

如上圖,在窗體中放入一個TclientDataSet控件提供資料、一個TdataSource控件、一個TDBGrid控件用來顯示文章标題清單,一個TDBEdit控件顯示文章标題,一個TDBMemo控件顯示文章内容,并設定它們之間的關系。

在TclientDataSet元件上單擊右鍵,選擇“Fields Editor”,在彈出的字段編輯器中單擊右鍵,選擇“New Field”,建一個名為Title的String類型字段和名為Article的Memo類型字段。再在TclientDataSet元件上單擊右鍵,選擇“Create DataBase”。至此一個模拟資料庫就建好了,您可以調用TclientDataSet的Delete,Edit,Insert等方法實作對資料庫操作了,還可以調用SaveToFile、LoadFromFile方法儲存、加載資料檔案了。

二、網頁分頁顯示技術

網頁分頁顯示技術比較簡單,我現在也說得口幹舌躁了,先給出代碼,你先自己分析一下吧!我将網頁分頁顯示封裝成了一個TarticlePublisher類,核心方法就是MakePublish方法,下面給出類的定義和MakePublish方法的代碼。

  TArticlePublisher = class(TObject)

  private

    FTitleWord: string;

    FIndexWord: string;

    FNumPerPage: Integer;

    FPageCount: Integer;

    FDataSet: TDataSet;

    FOutPutDir: string;

    FLinkFont: TFont;

    FUseDefFont: Boolean;

    FIndexTemplete: string;

    FLinkCSS: string;

    procedure FSetNumPerPage(AValue: Integer);

    procedure FSetLinkFont(AFont: TFont);

    procedure FSetUseDefFont(AValue: Boolean);

    procedure FSetIndexTemplete(AValue: string);

    procedure FSetLinkCSS(AValue: string);

  protected

    function AddFontToText(AText: string; AFont: TFont): string;virtual;

  public

    //輸出文章檔案的檔案名的開始幾個字元,預設為'art'

    property TitleWord: string read FTitleWord write FTitleWord;

    //輸出索引檔案的檔案名的開始幾個字元,預設為'ind'

    property IndexWord: string read FIndexWord write FIndexWord;

    //每頁的條目數,預設為30

    property NumPerPage: Integer read FNumPerPage write FSetNumPerPage;

    //總頁數,隻讀

    property PageCount: Integer read FPageCount;

    property DataSet: TDataSet read FDataSet write FDataSet;

    //輸出路徑

    property OutPutDir: string read FOutPutDir write FOutPutDir;

    //超連結字型

    property LinkFont: TFont read FLinkFont write FSetLinkFont;

    //使用預設字型

    property UseDefFont: Boolean read FUseDefFont write FSetUseDefFont;

    //索引頁模闆

    property IndexTemplete: string read FIndexTemplete write FSetIndexTemplete;

    //超連結CSS樣式

    property LinkCSS: string read FLinkCSS write FSetLinkCSS;

    constructor Create;

    procedure MakePublish;//開始轉化

  end;

procedure TArticlePublisher.MakePublish;

var

  LCount: Integer;

  i, j: Integer;

  LAriticleSL: TStringList;//儲存文章用

  LStrList: TStringList;//儲存動态頁面用

  LTempStr: string;

begin

  LCount := DataSet.RecordCount;

  DataSet.First;

  LAriticleSL := TStringList.Create;

  for i := 0 to LCount - 1 do

  begin

    LAriticleSL.Clear;

    LAriticleSL.Add(DataSet.FieldByName('Article').AsString);

    LAriticleSL.SaveToFile(Format('%s%s%d.htm',[OutPutDir,TitleWord,i]));

    DataSet.Next;

  LAriticleSL.Free;

  if LCount mod NumPerPage = 0 then

    FPageCount := LCount div NumPerPage

  else

    FPageCount := (LCount div NumPerPage) + 1;

  LStrList := TStringList.Create;

  for i := 1 to PageCount do

    LStrList.Clear;

    for j := 0 to NumPerPage - 1 do

    begin

      if DataSet.Eof then break;

      LStrList.Add('<p>');

      if LinkCSS = '' then

        LStrList.Add('<a href='+QuotedStr(TitleWord+IntToStr((i-1)*NumPerPage+j)+'.htm')+

          ' target=_blank>'+AddFontToText(DataSet.FieldByName('Title').AsString,LinkFont)+'</a>')

      else

          ' target=_blank style="'+LinkCSS+'">'+

            AddFontToText(DataSet.FieldByName('Title').AsString,LinkFont)+'</a>');

      LStrList.Add('</p>');

      DataSet.Next;

    end;

    if i <> 1 then

      LStrList.Add('<a href='+QuotedStr(IndexWord+IntToStr(i-1)+'.htm')+

        '>'+AddFontToText('上一頁', LinkFont)+'</a>');

    if i <> PageCount then

      LStrList.Add('<a href='+QuotedStr(IndexWord+IntToStr(i+1)+'.htm')+

        '>'+AddFontToText('下一頁', LinkFont)+'</a>');

    if IndexTemplete <> '' then

      LTempStr := AnsiReplaceText(IndexTemplete, INDEXTEMPLETESIGN, LStrList.Text);

      LStrList.Text := LTempStr;

    LStrList.SaveToFile(Format('%s%s%d.htm',[OutPutDir,IndexWord,i]));

  LStrList.Free;

end;

二、其他經驗

1、将字型Tfont儲存到Ini檔案的方法。

因為vcl的TFont隻是對windows FONT的封裝,它内部所存儲的資料隻是為了使使用者友善操作windows的font而定義的一些私有狀态資料,可以說這些資料與真正windows font中的資料風馬牛不相及,你儲存、恢複這些資料根本沒用(即使正确地恢複了這些資料也隻會得到一個錯誤的TFont對象)

要儲存TFont的内容并能正确恢複最簡單的方法是儲存TFont.Handle所對應font的具體結構,恢複時根據這個結建構立一個HFONT然後指派給TFont.Handle即可。

儲存字型:

  LFont: TFont;

  LLF: TLogFont;

  LMS: TMemoryStream;

…………

   …………

    LFont := Edit1.Font;

    GetObject(LFont.Handle, SizeOf(LLF), @LLF);

    LMS.Write(LLF, SizeOf(LLF));

    LMS.Position := 0;//不能丢了這句

    LIni.WriteBinaryStream('Config', 'LinkFont', LMS);

  …………

加載字型:

Begin

    LIni.ReadBinaryStream('Config', 'LinkFont', LMS);

    LMS.Read(LLF, SizeOf(LLF));

    LFont.Handle := CreateFontIndirect(LLF);

但是這樣還有一個問題就是字型中的字型名、字型大小等屬性都能正确的儲存,但是字型的顔色卻沒有儲存。分析TlogFont發現原來系統原生對象TlogFont中并沒有顔色這個字段值,字型顔色是VCL封裝上去的,是以需要另外再在Ini檔案增加一個字型顔色的項目。

2、為一段文字加上HTML字型

function AddFontToText(AText: string; AFont: TFont): string;

Const

  LTmpl = '<font face="%s" size="%d" color="#%s">%s</font>';//模闆

  LColorStr: string;

  LR, LG, LB: Integer;

  tmp: string;

    LR := GetRValue(AFont.Color);

    LG := GetGValue(AFont.Color);

    LB := GetBValue(AFont.Color);

    LColorStr := Format('%x%x%x',[LR,LG,LB]);

    tmp := Format(LTmpl,[AFont.Name, AFont.Size, LColorStr,AText]);

    if fsBold in AFont.Style then

      tmp := Format('<b>%s</b>',[tmp]);

    if fsItalic      in AFont.Style then

      tmp := Format('<i>%s</i>',[tmp]);

    if fsUnderline in AFont.Style then

      tmp := Format('<u>%s</u>',[tmp]);

    if fsStrikeOut in AFont.Style then

      tmp := Format('<StrikeOut>%s</StrikeOut>',[tmp]);

    result := tmp;

  

繼續閱讀