发表于2003-11-7 9:24:58
作者: dowms22 分类: 个人专区 密级: 公开 (评分: , 回复: 0, 阅读: 23) >>>> 一:TreeView.Items[0].Expanded := True; // 展开第一个节点 二:TreeView.Items[0].Item[0].Selected := True; // 移动到第一个节点的第一个子节点 找当前节点的下一个节点,按序号找如下: if treeview1.Selected.GetNext<>nil then treeview1.Selected.GetNext.Selected:=true; TreeView1.SetFocus; 找当前节点的下一个同层兄弟如下: if treeview1.Selected.getNextSibling<>nil then treeview1.Selected.getNextSibling.Selected:=true; TreeView1.SetFocus; TreeView.Selected.getPrevSibling //当前选中节点的上一个兄弟节点 TreeView.Selected.Parent // 当前选中节点的父节点 getfirstchild是跳到该节点子结点中的第一个 getlastchild是跳到该节点子结点中的最后一个 如果你是想跳到同层兄弟结点的第一个 if treeview1.selected.parent<>nil then treeview1.selected.parent.getfirstchild.selected:=true else treeview1.items.item[0].selected:=true; 如果你是想跳到同层兄弟结点的最后一个 if treeview1.selected.parent<>nil then treeview1.selected.parent.getlastchild.selected:=true else treeview1.Items.Item[treeview1.Items.Count-1].Selected:=true; TreeView的使用方法 基本信息: TreeView 是一个显示树型结构的控件,每一个节点都是一个新类, 使用具有代表性 每个节点都有四个值: TEXT:显示文字 Image Index:显示图形序号 Selected Index: State Index:
(1)建立目录项(本例中使用的TREEVIEW名称为:TvwTips) 增加根目录下的节点:(节点) var CatNode : TTreeNode; //先建立一个TREEVIEW使用的子对象 begin TvwTips.SetFocus; //将焦点置到这个TREEVIEW控件上 { 在根标题下建立一个新的子标题 } CatNode := TvwTips.Items.AddChild( TvwTips.Items.GetFirstNode,New Category ); CatNode.ImageIndex := 1; CatNode.SelectedIndex := 2; CatNode.EditText; { 允许用户改变这个标题 } end; 增加下一级目录(内容): var ParentNode, TipNode : TTreeNode; //先建立TREEVIEW使用 的子对象 VersionNum : Integer; begin TvwTips.SetFocus; //将焦点置到这个TREEVIEW控件上 VersionNum := TMenuItem( Sender ).Tag; { Ver num of new tip } ParentNode := TvwTips.Selected; { 取出当前的选中节点 } if ParentNode.Level = nlTip then{ Parent cannot be a tip node } ParentNode := TvwTips.Selected.Parent; TipNode := TvwTips.Items.AddChildObject( ParentNode,New Subject,Pointer( VersionNum ) ); TipNode.ImageIndex := 3; { Normal tip bitmap } TipNode.SelectedIndex := 4; { Highlighted tip bitmap } TipNode.MakeVisible; { Move new tip node into view } TipNode.EditText; { Immediately allow user to edit subject } EnableTreeViewFunctions( TipNode.Level ); RtfTip.Clear; RtfTip.Modified := False; end; (2)说明 TvwTips.Items.GetFirstNode 返回TREEVIEW的第一个节点,函数类型为 :TTreeNode TvwTips.Items.Count 返回当前TreeView的全部节点数,整数 TvwTips.Selected.Level 返回当前选中节点的在目录树中的级别, 根目录为0 TvwTips.Selected.Parent 返回当前选中节点上级节点,函数类型为 :TTreeNode 三、下面这段程序是用TREEVIEW连数据库及一些操作: unit bmzd; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, Db, DBTables, ImgList, Buttons, ExtCtrls, Grids, DBGrids; type Tfrmbmzd = class(TForm) Panel1: TPanel; cmd_new: TBitBtn; cmd_delete: TBitBtn; cmd_exit: TBitBtn; tvwcode: TTreeView; ScrollBox1: TScrollBox; GroupBox2: TGroupBox; Label3: TLabel; Label2: TLabel; Label1: TLabel; Label4: TLabel; Label5: TLabel; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Edit5: TEdit; ImageList1: TImageList; Edit1: TEdit; cmd_save: TBitBtn; cmd_update: TBitBtn; procedure FormShow(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure cmd_newClick(Sender: TObject); procedure cmd_deleteClick(Sender: TObject); procedure Edit2KeyPress(Sender: TObject; var Key: Char); procedure tvwcodeChange(Sender: TObject; Node: TTreeNode); procedure cmd_updateClick(Sender: TObject); procedure BitBtn2Click(Sender: TObject); procedure tvwcodeClick(Sender: TObject); private { Private declarations } function LoadCode(crTbl:TDBDataSet):Integer; function GetLevel(sFormat,sCode:String):Integer; public { Public declarations } end; var frmbmzd: Tfrmbmzd; ii:integer; tv:ttreenode; const SCodeFormat = 222222; //科目代码结构 SFirstNodeTxt = 部门分类; implementation uses dm; {$R *.DFM}
function tfrmbmzd.LoadCode(crTbl:TDBDataSet):Integer; var NowID,sName,ShowTxt:String; i,Level:Integer; MyNode:array[0..6]of TTreeNode; //保存各级节点,最长支持6级(重点) begin Screen.Cursor:=crHourGlass; Level:=0; With frmdm.tabbm do begin try if not Active then Open; First; tvwCode.Items.Clear; //以下是增加第一项 MyNode[Level]:=tvwCode.Items.Add (tvwCode.TopItem,SFirstNodeTxt); MyNode[Level].ImageIndex:=0; MyNode[Level].SelectedIndex:=0; //以上是增加第一项 While Not Eof do begin NowID:=Trim(FieldByName(bumeng_id).AsString); ShowTxt:=FieldByName(bumeng_name).AsString; Level:=GetLevel(SCodeFormat,NowID); //返回代码的级数 //以下是增加子项 //以下用上一级节点为父节点添加子节点 if Level>0 then//确保代码符合标准 begin MyNode[Level]:=tvwCode.Items.AddChild (MyNode[Level-1],NowID+ +ShowTxt); MyNode[Level].ImageIndex:=1; MyNode[Level].SelectedIndex:=2; end; //以上是增加子项 Next; end; finally Close; end; end; MyNode[0].Expand(False);//将首节点展开 Screen.Cursor:=crDefault; end; //以上函数将Code.db表中的科目代码和科目代码名称显示出来 //下面函数的功能是返回一代码的级数, //参数sFormat传递科目代码结构; //参数sCode传递某一科目代码 function tfrmbmzd.GetLevel (sFormat,sCode:String):Integer; var i,Level,iLen:Integer; begin Level:=-1;//如果代码不符合标准,则返回-1 iLen:=0; if (sFormat<>)and(sCode<>)then for i:=1 to Length(sFormat) do begin iLen:=iLen+StrToInt(sFormat[i]); if Length(sCode)=iLen then begin Level:=i; Break; end; end; Result:=Level; end; procedure Tfrmbmzd.FormShow(Sender: TObject); begin if not frmdm.tabbm.active then frmdm.tabbm.Open; frmdm.tabbm.IndexFieldNames:=BUMENG_ID; //按字段aCode排序(不要漏掉) LoadCode(frmdm.tabbm); end; procedure Tfrmbmzd.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; procedure Tfrmbmzd.cmd_newClick(Sender: TObject); begin tvwcode.SetFocus ; if tvwcode.selected.AbsoluteIndex<>0 then begin cmd_delete.Enabled:=true; cmd_update.Enabled:=true; cmd_save.Enabled :=true; if not frmdm.tabbm.Active then frmdm.tabbm.Open; edit1.text:=frmdm.tabbm.Fields[0].asstring; end; tvwcode.SetFocus ; tvwcode.Items.AddChild(tvwcode.selected,新建部门); if tvwcode.Selected.HasChildren then begin if tvwcode.Selected.GetLastChild.index+1>9 then edit2.text:=inttostr(tvwcode.Selected.GetLastChild.index+1) else edit2.text:=0+inttostr(tvwcode.Selected.GetLastChild.index+1); edit3.text:=新建部门; edit2.Enabled:=true; edit3.Enabled:=true; end else begin edit2.text:=01; edit3.text:=新建部门; edit2.Enabled:=true; edit3.Enabled:=true; end; if not frmdm.tabbm.Active then frmdm.tabbm.Open; frmdm.tabbm.edit; frmdm.tabbm.Append; cmd_new.Enabled :=false; cmd_delete.Enabled :=false; cmd_update.Enabled :=false; cmd_save.Enabled :=true; //新建下级部门 tvwcode.Selected.GetLastChild.Selected:=true; //设选择 tv:=tvwcode.Selected ; tvwcode.autoExpand:=true; tvwcode.SetFocus ; end;
procedure Tfrmbmzd.cmd_deleteClick(Sender: TObject); var I:integer; seno,setext:string; begin if tvwcode.Selected.HasChildren=true then begin application.messagebox(该部门包含下级,不能删除,提示,MB_OKCANCEL+mb_iconquestion ) ; end else begin if application.messagebox(你确实要删除当前部门吗,提示,MB_OKCANCEL+mb_iconquestion )=IDOK then begin setext:=tvwcode.selected.text; i:=0; while setext[i] <> do begin I := I + 1; seno:=seno+setext[i]; end; if not frmdm.tabbm.Active then frmdm.tabbm.Open; frmdm.tabbm.setkey; frmdm.tabbm.Fields[0].asstring:=seno; if frmdm.tabbm.GotoKey then begin frmdm.tabbm.edit; frmdm.tabbm.Delete; end; tvwcode.Selected.Delete ; cmd_new.Enabled :=true; tvwcode.autoExpand:=true; tvwcode.SetFocus ; end; end; end; procedure Tfrmbmzd.Edit2KeyPress(Sender: TObject; var Key: Char); begin if key in [0..9,Chr(vk_Back)] then else begin key:=#0; application.messagebox(,,mb_ok); end; end; procedure Tfrmbmzd.tvwcodeChange(Sender: TObject; Node: TTreeNode); var i,lev:integer ; strr,seno,setext:string; begin if cmd_new.Enabled =true then begin if tvwcode.selected.AbsoluteIndex<>0 then begin cmd_delete.Enabled:=true; cmd_update.Enabled:=true; cmd_save.Enabled :=true; setext:=tvwcode.selected.text; i:=0; while setext[i] <> do begin I := I + 1; seno:=seno+setext[i]; end; if not frmdm.tabbm.Active then frmdm.tabbm.Open; frmdm.tabbm.setkey; frmdm.tabbm.Fields[0].asstring:=seno; frmdm.tabbm.GotoKey; strr:=; case tvwcode.Selected.Level of 2: strr:=copy(frmdm.tabbm.fields[0].asstring,1,2); 3: strr:=copy(frmdm.tabbm.fields[0].asstring,1,4); end; edit1.text:=strr; //加上级编码 edit3.text:=frmdm.tabbm.Fields[1].asstring; //本级编码 edit2.text:=copy(frmdm.tabbm.fields[0].asstring,length(frmdm.tabbm.fields[0].asstring)-1,2); end else begin edit1.text :=; edit2.text :=; edit3.text :=部门分类; cmd_delete.Enabled :=false; cmd_update.Enabled :=false; end; end; end; procedure Tfrmbmzd.cmd_updateClick(Sender: TObject); var i:integer; begin for i:=0 to ComponentCount-1 do begin if (Components[I] is tedit ) then (Components[I] as tedit).enabled:=false; end; for i:=0 to ComponentCount-1 do begin if (Components[I] is tbitbtn ) then (Components[I] as tbitbtn).enabled:=true; end; if tvwcode.Selected.AbsoluteIndex<>0 then begin
if not frmdm.tabbm.Active then frmdm.tabbm.Open; frmdm.tabbm.Edit; frmdm.tabbm.Fields[0].asstring:=edit1.text+edit2.text; frmdm.tabbm.Fields[1].asstring:=edit3.text; try frmdm.tabbm.Post; //表的保存 except on edbengineerror do begin edit2.Enabled :=true; application.messagebox(编号不能重复,请重新输入,提示,MB_OK+mb_iconquestion ) ; exit; end; end; tvwcode.Selected.Text:=edit1.text+edit2.text+ +edit3.text; tvwcode.SetFocus ; //修改树 end; cmd_new.Enabled :=true; edit2.Enabled :=false; end; procedure Tfrmbmzd.BitBtn2Click(Sender: TObject); begin cmd_new.Enabled :=false; cmd_delete.Enabled :=false; edit2.enabled:=true; edit3.Enabled :=true; end; procedure Tfrmbmzd.tvwcodeClick(Sender: TObject); var i:integer; begin if cmd_new.Enabled =false then begin application.MessageBox(当前是修改状态,请单击保存按钮,提示,mb_ok); tv.Selected :=true; end; if tvwcode.selected.AbsoluteIndex=0 then begin for i:=0 to ComponentCount-1 do begin if (Components[I] is tedit ) then (Components[I] as tedit).enabled:=false; end; for i:=0 to ComponentCount-1 do begin if (Components[I] is tbitbtn ) then (Components[I] as tbitbtn).enabled:=false; cmd_new.Enabled :=true; cmd_exit.Enabled :=true; end; end; end; end 四、使用概述 树形图(Treeview)是Win95下新增加的通用显示部件(Common Control,在COMCTL32.DLL中)之一,从Delphi2.0开始也增加了相应的控件Treeview,用于取代原Outline控件。由于树形图结构较复杂,使用起来常不知如何下手。这里就使用中的一些问题作些介绍。 Treeview用于显示按照树形结构进行组织的数据,这在实际当中用途还是比较广泛的,如计算机中的文件系统(Windows95中的资源管理器)、企业或公司的组成结构等等。Treeview控件中一个树形图由节点(TreeNode)和连接线组成。TtreeNode是TTreeview的基本组成单元。一个树的节点又包含文本(Text)和数据(Data)。Text为String类,Data则为无定形指针(Untyped Pointer),可以指向一个与节点相联系的数据结构。 每一个节点下子节点形成这一节点的Items属性,当前节点有一个唯一的Index(TreeNode的Index属性),用于说明子节点在Items中的位置,每一个节点下的子节点是顺序编号的,第一个是0,第二个是1,依次类推。用IndexOf方法获得子节点的顺序,绝对顺序(AbsoluteIndex)则是指从Treeview第一个项开始的顺序值,第一个是0,如此推下去。Item属性则根据Index的值返回当前节点的第Index个子节点。Count则表明属于此项的所有子节点的数量。用MoveTo方法将Item由一个位置移到另一个位置。 Expanded属性表明是否所有的子项都全部展开(包括子项的子项),为True表示全部展开。IsVisible属性表明一个项是否在树中能被看到,如果树全部展开那么这个Item是肯定可以被看到。HasChildren属性表明一个项是否有子项。 GetFirstChild, GetLastChild, GetPrevChild, and GetNextChild分别返回当前项子项的第一个、最后一个和前一个、后一个项。GetNextSibling and GetPrevSibling则返回在同一Level下的下一个和上一个项。GetNextVisible and GetPrevVisible则返回能看得到的下一个和上一个项。如果一个节点有Parent,则HasAsParent方法返回True. Parent为当前项的父项。Focused属性确定焦点是否落在此节点上,被Focus时会一个标准的方框围住。很显然,只有一个节点会被聚焦。 Selected属性表明一个节点是否被选中,同样只有一个节点会被选中。DropTarget属性表明节点在拖动操作中是源还是目标。 1.添加、删除、修改节点: 静态的方法可以在设计时通过Items的编辑器设置各节点的内容。 在添加和删除前必须保证有节点被选中(Treeview.Selected = nil) 用AddFirst, AddFirstChild, AddChild等先添加根节点,如Treeview.Items.AddFirst( nil, Root); 然后以此为基础,添加此项的子节点。 删除节点 Treeview.Selected.Delete 编辑节点内容 Treeview.Selected.EditText 注意:由于根节点没有父节点 (TTreeNode.Parent= nil) 此外,在大批量添加数据到Treeview中时最好使用 TreeView.Items.BeginUpdate; 添加节点 TreeView.Items.EndUpdate 这样能加快显示速度。 2.在节点上添加图象 Treeview中几个与图象相关的属性: SelectedIndex:当节点被选中时在TimageList 中选什么样的图象 OverlayIndex:选那副图象作为掩图(一幅图象透明地显示在另一幅图象的前面),比如一个节点不可用时加一副X图象在其前面。 ImageIndex:在常态时选用的图的序号 StateIndex: 在StateImages这个ImageList中对应的序号,-1时不显示图象 比较典型的,象在文件管理器中的所显示的一样,Treeview控件在节点之前也可以显示图象。在Form中放置一ImageList控件,加入几个图片,分别被Index为0,1,…在Treeview的Image属性项填入你所加入的ImageList的控件名称。TreeNode的ImageIndex表示节点未被选中时(Selected=nil)的图片序号,SelectedIndex表示节点被选中时图片序号。 3.关于Level Level的概念可以用下图表示: Level0 Level1 Level2 4.排序 SortType决定什么时候进行排序; TreeView.AlphaSort对节点进行排序,如果不能满足要求,你可以定义自己的CustomSort方法。 5.Drag&Drop操作,与标准的拖放操作使用方法一样。 五、一个例子: 首先,在库的构建上要有一定策略以下几个字段非常重要: codeID 代码集名称 (例如:AB) code 节点代码 (例如:新疆节点的代码为65,乌鲁木齐的节点代码为6501等) description 节点描述 (例如:如上面的新疆、乌鲁木齐等) pptr 父节点代码 (例如:乌鲁木齐节点的父代码为65,最高层节点的父节点代码可同其代码集,例如:新疆的父节点为 AB) cptr 子节点标识 (例如:该节点是否有下级节点,有则取值1,没有则取值0) 建立树由两部分构成: procedure TForm1.FormActivate(Sender: TObject); var code_ID,new_sql,node_text,table_name:string; new_node:Ttreenode; begin //要传递的参数 code_ID:=AB; table_name:=sr_codeitem; //******** treeview1.Items.BeginUpdate; //清空所有项目 treeview1.Items.Clear; new_sql:=select * from + table_name + where codeID=++code_ID+ + and +pptr=++code_ID+;
//数据集中先筛选出所有要增加节点 with dm1.Query1 do begin close; sql.Clear; sql.Add(new_sql); open; //增加第一层节点 while not eof do begin node_text:=fieldbyname(code).asstring; node_text:=node_text+ +fieldbyname(description).asstring; new_node:=treeview1.Items.add(nil,node_text); new_node.HasChildren:=true; next; end;//end while end;//end with
treeview1.Items.EndUpdate; end; procedure TForm1.TreeView1Expanding(Sender: TObject; Node: TTreeNode; var AllowExpansion: Boolean); var new_sql,node_text,child_text,code_ID,table_ID:string; child_node:Ttreenode; begin //获取参数 code_ID:=AB; table_ID:=sr_codeitem; treeview1.Items.BeginUpdate; node_text:=node.Text; //截取所点击节点的code node_text:=copy(node_text,1,pos( ,node_text)-1); with dm1.Query1 do begin close; sql.Clear; new_sql:=select * from +table_ID+ where pptr=++node_text+ + and codeID= ++code_ID+; sql.Add(new_sql); open;//定位所点的项 //清除原来的下级节点 node.DeleteChildren; while not eof do begin//增加下级节点 child_text:=fieldbyname(code).asstring+ +fieldbyname(description).asstring; child_node:=treeview1.Items.AddChild(node,child_text); if fieldbyname(cptr).asstring=1 then child_node.HasChildren:=true; next; end;//end while end;//end with treeview1.Items.EndUpdate; end; 第二部分:在 treeview 的onExpanding 事件中添加如下代码 procedure TForm1.TreeView1Expanding(Sender: TObject; Node: TTreeNode; var AllowExpansion: Boolean); var new_sql,node_text,child_text,code_ID,table_ID:string; child_node:Ttreenode; begin //获取参数 code_ID:=AB; table_ID:=sr_codeitem; treeview1.Items.BeginUpdate; node_text:=node.Text; //截取所点击节点的code node_text:=copy(node_text,1,pos( ,node_text)-1); with dm1.Query1 do begin close; sql.Clear; new_sql:=select * from +table_ID+ where pptr=++node_text+ + and codeID= ++code_ID+; sql.Add(new_sql); open;//定位所点的项 //清除原来的下级节点 node.DeleteChildren; while not eof do begin//增加下级节点 child_text:=fieldbyname(code).asstring+ +fieldbyname(description).asstring; child_node:=treeview1.Items.AddChild(node,child_text); if fieldbyname(cptr).asstring=1 then child_node.HasChildren:=true; next; end;//end while end;//end with treeview1.Items.EndUpdate; end; 六、让我们一个一个来回答: 第一个:取出节点的text属性值,赋给Richedit的Lines.text即可; 例如: self.RichEdit1.Lines.text:= self.Treeview1.selected.text; 第二个:TtreeView控件有函数保存和载入树的结构到文件 例如:self.Treeview1.SaveToFile(文件名);//保存结构 self.TreeView1.LoadFromFile(文件名);//载入结构 第三个:TreeView的每个节点都有ItemID(句柄),AbsoluteIndex(相对于树头节点的索引位置), Index(在当前层的位置),Level(本节点的层数)通过访问这些可以知道其位置; 例如:self.TtreeView1.selected.ItemID;//返回句柄 self.TreeView1.selected.Level;//返回层数 self.TreeView1.Items.count//返回所有节点的个数; **寻找某一个节点的话,就只有写一个循环来遍历整个树,直到找到符合条件的节点为止, 关于查找节点的代码我也在想,先参考上面同志们的回答吧; ??**为某个节点加上子节点,例如: var NewNode:TTreeNode; begin NewNode:=self.Treeview1.Items.addChild(self.Treeview1.Items[3],新的字节点); //为self.Treeview1.Items[3]加上一个字节点,标签是新的字节点, //还有其他的ADD方法,可以查找Delphi帮助 //然后可以给刚加上去的子节点赋值; NewNode.ImageIndex:=n; NewNode.SelectedIndex:=M; NewNode.Data:=X;//注意X是一个指针类型;关于这方面的帮助 //可以找一下TTreeNode.Data 属性例子 end; ??**想选中某个节点:self.TreeView1.Items[n].selected:=true;//这样就选中了 ??**展开某节点就容易了:self.TreeView1.Items[n].Expand;//展开啦! //想合上就用Collapse(Recurse: Boolean)函数, 总之呢,去查一下TtreeNode的帮助吧! ??**清除某节点下的所有子节点,用DeleteChildren是没错的,例如: self.Treeview1.Items[n].DeleteChildren;//OK,下面都没了! 七、query1.close; query1.sql.clear; query1.sql.add(select * from t08 order by t0801); try query1.open; except on e:exception do begin application.MessageBox(pchar(打开数据库文件失败!+#13+#13+e.Message),错误信息,16); close; exit; end; end; //创建结构树 while not query1.eof do begin s:=trim(query1.fields[0].asstring); case length(s) of 2:begin tv1.Selected:=tv1.items.add(nil,trim(query1.fields[1].asstring)); tv2.Selected:=tv2.items.add(nil,trim(query1.fields[0].asstring)); end; 4:begin p1:=tv1.items.addchild(tv1.Selected,trim(query1.fields[1].asstring)); p2:=tv2.items.addchild(tv2.Selected,trim(query1.fields[0].asstring)); end; 6:begin tv1.Items.addchild(p1,trim(query1.fields[1].asstring)); tv2.Items.addchild(p2,trim(query1.fields[0].asstring)); end; end; query1.next; end; query1.close; if tv1.Items.Count>0 then begin tv1.Selected:=tv1.Items[0]; tv1.Selected.Expand(true); end; tv1.OnClick(self); 八、clear速度慢的问题 问题的关键在于Clear方法会一个一个地删除每个Node, 于是TreeView不断刷新,所以速度就.... 代码修正一下: with MyTreeView.Items do try BeginUpdate; Clear; finally EndUpdate; end; 另外 1、你现在遇到的问题是大量删除, 如果是大量插入,也应该同样处理 2、ListView有同样问题,注意 其他Windows控件也有,但不很明显 比如Memo、RichEdit等等 总之,凡大量数据修改的情况下, 应该注意BeginUpdate和EndUpdate 3、BeginUpdate和EndUpdate应该一一对应, 因为Delphi实际上是用计数器来处理的, 如果忘了EndUpdate, 或者BeginUpdate比EndUpdate次数多, 可能导致控件不刷新了 九、用treeview做权限管理 http://www.delphibbs.com/delphibbs/dispq.asp?lid=2242766
|