现在网上有很多提供主页空间的站点,但是大部分低价位的站点只提供静态 HTML 文档的功能,不支持 ASP PHP 等动态网页技术。如果您像在您的主页上放上您喜欢的文章,那么需要一个一个链接的做。如果您删除了某篇文章或者想添加某篇文章,那么需要做很多改动,牵一发而动全身。
  凌科文章动态发布系统就是为你解决这个问题而开发的软件。使用本软件后您可以轻易生成下面效果的网页。
///
Delphi 的使用帮助文件
 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

最后一篇情书
 

上一页
//
凌科文章动态发布预览
 

凌科文章动态新技术发
 

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

软件的界面如下:
 
 

这款软件有两项关键性技术:瘦客户端的数据库应用和网页分页显示技术。其中的瘦客户端的数据库应用在我的另一款软件《凌科网页精灵》的“程序自动升级”功能中也有所应用。
一、 瘦客户端的数据库应用
本软件的一个基本要求就是用户可是随时在工程添加、删除文章,并能将工程保存到文件中,并可以在以后打开工程文件后继续编辑工程。实现这个功能可以有很多中解决方案:
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;
  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 文件的方法。

因为 vcl TFont 只是对 windows FONT 的封装,它内部所存储的数据只是为了使用户方便操作 windows font 而定义的一些私有状态数据,可以说这些数据与真正 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;