“动态文章发布系统”开发手记

“动态文章发布系统”开发手记
 

现在网上有很多提供主页空间的站点,但是大部分低价位的站点只提供静态HTML文档的功能,不支持ASPPHP等动态网页技术。如果您像在您的主页上放上您喜欢的文章,那么需要一个一个链接的做。如果您删除了某篇文章或者想添加某篇文章,那么需要做很多改动,牵一发而动全身。

  凌科文章动态发布系统就是为你解决这个问题而开发的软件。使用本软件后您可以轻易生成下面效果的网页。

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

Delphi的使用帮助文件

 

最后一篇情书

 

上一页

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

凌科文章动态发布预览

 

凌科文章动态新技术发

 

下一页

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

点击相应的文章标题(如"最后一篇情书 ")就会弹出一个窗口显示这篇文章。

 

软件的界面如下:

 

 aap1.jpg

这款软件有两项关键性技术:瘦客户端的数据库应用和网页分页显示技术。其中的瘦客户端的数据库应用在我的另一款软件《凌科网页精灵》的“程序自动升级”功能中也有所应用。

一、瘦客户端的数据库应用

本软件的一个基本要求就是用户可是随时在工程添加、删除文章,并能将工程保存到文件中,并可以在以后打开工程文件后继续编辑工程。实现这个功能可以有很多中解决方案:

1  定义一个结构体TariticleItem(因为要将文章保存到ListBoxItem属性中,所以要用类来模拟结构体)

TariticleItem = class

Public

  Title: string;

  Ariticle: string;

End;

将用户输入的标题和文章正文存储在一个TariticleItem,然后再调用ListBox.Item.Add()将此TariticleItem保存到ListBox 中,在保存工程的时候遍历ListBox中每个项目然后保存到文件。在加载工程文件时也类似的遍历项目。

但是这样会使工作量变得很大,况且很有可能出现内存问题(我猜测的,没有实践),而且保存的工程文件格式也会很难确定。

2)用AccessMDB数据库存储文章,通过ADO操作数据库。之所以选择ADO访问Access数据库而不使用BDE的原因就是BDE的配置十分麻烦,在这种小规模的程序中使用BDE有点恐怖。而AccessADO驱动在Win98以上操作系统中一般都有安装,这样就免去了配置的麻烦。而且使用TADOTableTADOQuerySaveToFileLoadFromFile方法也可以轻易实现数据导出/导入文件。但是为什么我们不使用它呢?因为“Win98以上操作系统” “一般”都有安装,这就说明Win95的用户就不能使用本软件了(现在还是有很多Win95用户的),而且即使是Win98以上的系统也不能保证一定装有ADO驱动。

3)使用Delphi中的TclientDataSet 控件。TClientDataSet控件继承自TDataSet,具有所有数据集组件的基本功能,而且还有自己的很多很有用的功能,它是一款基于文件型数据存储和操作的控件,数据可以导出到文件中(支持xmlcds两种文件格式)。该控件封装了对数据进行操作处理的接口和功能,具有ADO的上述优点,基本上能满足单机""数据库应用程序的需要。Delphi5的用户在发布软件时只要同时发布Midas.dll就可以了,Delphi6Delphi7的用户只要在工程文件中包含MidasLib单元,Midas.dll的功能就集成在应用程序中了(会使程序增大200K左右),成为真正的零配置软件。况且使用TclientDataSet控件,我们就可以使用数据敏感组件,我们又免去了处理将保持用户输入数据更新的问题。基于以上原因,我决定使用TclientDataSet控件。

aap2.jpg

如上图,在窗体中放入一个TclientDataSet控件提供数据、一个TdataSource控件、一个TDBGrid控件用来显示文章标题列表,一个TDBEdit控件显示文章标题,一个TDBMemo控件显示文章内容,并设定它们之间的关系。

TclientDataSet组件上单击右键,选择“Fields Editor,在弹出的字段编辑器中单击右键,选择“New Field”,建一个名为TitleString类型字段和名为ArticleMemo类型字段。再在TclientDataSet组件上单击右键,选择“Create DataBase”。至此一个模拟数据库就建好了,您可以调用TclientDataSetDelete,Edit,Insert等方法实现对数据库操作了,还可以调用SaveToFileLoadFromFile方法保存、加载数据文件了。

二、网页分页显示技术

网页分页显示技术比较简单,我现在也说得口干舌躁了,先给出代码,你先自己分析一下吧!我将网页分页显示封装成了一个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;

  end;

  LAriticleSL.Free;

 

  if LCount mod NumPerPage = 0 then

    FPageCount := LCount div NumPerPage

  else

    FPageCount := (LCount div NumPerPage) + 1;

 

  LStrList := TStringList.Create;

  DataSet.First;

 

  for i := 1 to PageCount do

  begin

    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

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

          ' 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

    begin

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

      LStrList.Text := LTempStr;

    end;

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

  end;

  LStrList.Free;

end;

二、其他经验

1将字体Tfont保存到Ini文件的方法。

因为vclTFont只是对windows FONT的封装,它内部所存储的数据只是为了使用户方便操作windowsfont而定义的一些私有状态数据,可以说这些数据与真正windows font中的数据风马牛不相及,你保存、恢复这些数据根本没用(即使正确地恢复了这些数据也只会得到一个错误的TFont对象)

要保存TFont的内容并能正确恢复最简单的方法是保存TFont.Handle所对应font的具体结构,恢复时根据这个结构创建一个HFONT然后赋值给TFont.Handle即可。

保存字体:

var

  LFont: TFont;

  LLF: TLogFont;

  LMS: TMemoryStream;

…………

begin

   …………

    LFont := Edit1.Font;

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

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

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

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

  …………

end;

加载字体:

var

  LFont: TFont;

  LLF: TLogFont;

  LMS: TMemoryStream;

Begin

  …………

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

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

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

    LFont.Handle := CreateFontIndirect(LLF);

…………

End;

但是这样还有一个问题就是字体中的字体名、字体大小等属性都能正确的保存,但是字体的颜色却没有保存。分析TlogFont发现原来系统原生对象TlogFont中并没有颜色这个字段值,字体颜色是VCL封装上去的,所以需要另外再在Ini文件增加一个字体颜色的项目。

2、为一段文字加上HTML字体

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

Const

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

var

  LColorStr: string;

  LR, LG, LB: Integer;

  tmp: string;

begin

    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;

end;

 

 

 

 

 
  

 

 

 

 

 

你可能感兴趣的:(“动态文章发布系统”开发手记)