VST实例(1)

一、程序目标

首先谈谈我们的目标程序,这个程序是通过读取一个CSV文件,创建一个两层结构的目录树,第一层存放的是情报区名称,而第二层存放的是该情报区的机场信息。

每一层(level)的每一个节点(node)分为6栏(column),最终的运行结果如图所示:

 

 程序实现了:

l         创建目录树

l         分栏显示不同的信息

l         不同的类型使用了不同的图标

l         不同的底色显示

l         在编辑框里输入字符,实时筛选。

l         同一栏中使用不同的显示。

l         可以调节行、列宽度

l         标题栏菜单

l         添加或修改内容

l         ……

而程序设计阶段的界面如下

 准备创建一个两层结构的关于机场列表的目录树,数据来源于一个CSV文件,但鉴于SQLITE强大的查询功能,所以首先要做的就是把CSV文件中的数据添加到SQLITE数据库中。

现在让我们一步步的开始程序的设计吧。

首先来介绍下CSV文件中的数据,CSV文件中存储了若干机场的基础数据,包括机场的ICAO四字码,IATA三字码,中文名称,所属情报区,该机场是否是单跑道机场以及该机场是主降机场还是备降机场。同时,还存储了情报区的ICAO四字码和中文名称,当然情报区不包含IATA三字码,也不存在跑道数,所以三字码部分是空白字符串,而跑道数是-1。

程序设计阶段的界面很简单,如图所示:

 

 程序的功能基本上都靠代码来实现,imagelist(IL1)中添加了三个32*32的图标,只使用其中两个。

目录树使用的控件是TVirtualStringTree(VST),其它Firedac等控件的设置如下:

 

object Form2: TForm2
  Left = 0
  Top = 0
  Caption = 'Form2'
  ClientHeight = 587
  ClientWidth = 861
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object vst: TVirtualStringTree
    Left = 0
    Top = 50
    Width = 861
    Height = 537
    Align = alClient
    Header.AutoSizeIndex = -1
    Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoHeaderClickAutoSort, hoAutoColumnPopupMenu]
    Header.PopupMenu = vthdrpmn1
    Header.SortColumn = 0
    HintMode = hmHintAndDefault
    Images = il1
    IncrementalSearch = isAll
    LineMode = lmBands
    LineStyle = lsSolid
    ParentShowHint = False
    PopupMenu = pm1
    ShowHint = True
    TabOrder = 0
    TreeOptions.AutoOptions = [toAutoDropExpand, toAutoExpand, toAutoScroll, toAutoScrollOnExpand, toAutoSort, toAutoSpanColumns, toAutoTristateTracking, toAutoHideButtons, toAutoChangeScale]
    TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toEditable, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag, toNodeHeightResize, toEditOnClick]
    TreeOptions.PaintOptions = [toShowBackground, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowRoot, toShowVertGridLines, toThemeAware, toUseBlendedImages, toShowFilteredNodes]
    TreeOptions.SelectionOptions = [toFullRowSelect]
    OnBeforeItemErase = vstBeforeItemErase
    OnBeforeItemPaint = vstBeforeItemPaint
    OnCompareNodes = vstCompareNodes
    OnCreateEditor = vstCreateEditor
    OnDragAllowed = vstDragAllowed
    OnDragOver = vstDragOver
    OnDragDrop = vstDragDrop
    OnDrawText = vstDrawText
    OnEditing = vstEditing
    OnGetText = vstGetText
    OnPaintText = vstPaintText
    OnGetHintKind = vstGetHintKind
    OnGetImageIndex = vstGetImageIndex
    OnGetHint = vstGetHint
    OnGetNodeDataSize = vstGetNodeDataSize
    OnInitChildren = vstInitChildren
    OnInitNode = vstInitNode
    OnNewText = vstNewText
    OnNodeClick = vstNodeClick
    OnNodeDblClick = vstNodeDblClick
    Columns = <
      item
        Position = 0
        Width = 857
      end>
  end
  object pnl1: TPanel
    Left = 0
    Top = 0
    Width = 861
    Height = 50
    Align = alTop
    Caption = 'pnl1'
    ShowCaption = False
    TabOrder = 1
    OnClick = pnl1Click
    object lbledt1: TLabeledEdit
      Left = 128
      Top = 23
      Width = 553
      Height = 21
      EditLabel.Width = 108
      EditLabel.Height = 13
      EditLabel.Caption = #35831#36755#20837#24182#22238#36710#26597#25214#65306
      LabelPosition = lpLeft
      TabOrder = 0
      OnChange = lbledt1Change
      OnEnter = lbledt1Enter
    end
  end
  object fdphysqltdrvrlnk1: TFDPhysSQLiteDriverLink
    Left = 792
    Top = 400
  end
  object con1: TFDConnection
    Params.Strings = (
      'DriverID=SQLite')
    Left = 792
    Top = 336
  end
  object dlgOpen1: TOpenDialog
    FileName = 'codes.csv'
    Left = 784
    Top = 464
  end
  object QRY1: TFDQuery
    Connection = con1
    Left = 720
    Top = 400
  end
  object fdgxwtcrsr1: TFDGUIxWaitCursor
    Provider = 'Forms'
    Left = 720
    Top = 344
  end
  object QRY2: TFDQuery
    Connection = con1
    Left = 712
    Top = 464
  end
  object il1: TImageList
    Height = 32
    Width = 32
    Left = 776
    Top = 264
    Bitmap = {......}
  end
  object vthdrpmn1: TVTHeaderPopupMenu
    Left = 792
    Top = 57
  end
  object pm1: TPopupMenu
    OnPopup = pm1Popup
    Left = 584
    Top = 472
    object N1: TMenuItem
      Caption = #20840#23637#24320
      OnClick = N1Click
    end
    object N2: TMenuItem
      Caption = #20840#25910#25314
      OnClick = N2Click
    end
    object N3: TMenuItem
      Caption = '-'
    end
    object CSV1: TMenuItem
      Caption = #21478#23384#20026'CSV'#25991#20214
      OnClick = CSV1Click
    end
    object HTML1: TMenuItem
      Caption = #20854#23427#25991#26412
      OnClick = HTML1Click
    end
    object N4: TMenuItem
      Caption = '-'
    end
    object N5: TMenuItem
      Caption = #23548#20986#21246#36873#26426#22330#20449#24687
      OnClick = N5Click
    end
  end
  object dlgSave1: TSaveDialog
    Filter = 
      #32593#39029#25991#20214'UTF-8 (*.htm; *.html)|*.htm;*.html|Unicode UTF-16 text file ' +
      '(*.uni)|*.uni|Rich text UTF-16 file (*.rtf)|*.rtf|CSV'#25991#20214' (*.csv)|' +
      '*.csv|'#25991#26412#25991#20214' (*.txt)|*.txt'
    Left = 704
    Top = 280
  end
end

二、初始数据设置

首先创建一个record类型RCODES及其指针如下:

type
  RCODES=record
    ICAO:String;
    IATA:String;
    CODETYPE:String;
    rwy_style:String;
    names:string;
    apt_type:string;
  end;
  pcodes=^RCODES;

VST需要你首先告诉它你的数据的长度,这一点是必须的,我们需要为ongetnodedatasize事件写代码如下:

procedure TForm2.vstGetNodeDataSize(Sender: TBaseVirtualTree;  var NodeDataSize: Integer);
begin
  NodeDataSize:=SizeOf(rcodes);
end;

也可以在创建窗体的时候进行设置:

VST. NodeDataSize:=SizeOf(rcodes);

数据来源于一个CSV文件,我们当然可以直接处理CSV文件的数据,但是这个文件的数据结构不是很清晰,我习惯性的把文件转换为SQLITE数据库进行处理,所以在创建窗体的时候首先有以下代码:

procedure TForm2.FormCreate(Sender: TObject);
var sl1:TStringList;sl2:tarray<string>;ss1,ss2:string; i:Integer;
    //nd:PVirtualNode;
begin
   con1.Params.Values['database']:='codes.db';
   //如果没有SQLITE数据库,则找到CSV文件并创建数据库和表,表名为codes
   //创建的表中增加了一个新字段:RMK以备用。
   if not FileExists('codes.db') then
   begin
      sl1:=TStringList.Create;
      if not dlgOpen1.Execute then  close;
      sl1.LoadFromFile(dlgOpen1.FileName);
      ss1:=sl1[0];
      sl2:=ss1.Split([',']);
      ss2:='create table codes(';
      for ss1 in sl2 do
        ss2:=ss2+ss1+' ftstring,';
      ss2:=ss2+'rmk ftstring)';
     con1.ExecSQL(ss2);
     for i:=1 to  sl1.Count-1 do
       begin
         ss1:=sl1[i];
         sl2:=ss1.Split([',']);
         ss2:='insert into codes values(';
         for ss1 in sl2 do
           ss2:=ss2+ss1.QuotedString+',';
         ss2:=ss2+'" ")';
         Con1.ExecSQL(ss2);

       end;
       //创建的SL1最好释放
       FreeAndNil(SL1);
   end;
   //设置节点的默认高度,这个默认值是18,我们在这里改为30
   vst.DefaultNodeHeight:=30;
   //设置header标题栏
   with vst.Header do
   begin
     //header的Options进行一些初始设置,分别是:
     //hoColumnResize 可以修改栏的尺寸
     //hoShowSortGlyphs 排序时可以显示一个向上或向下的三角形
     //hoHeaderClickAutoSort 可以通过点击标题栏进行排序,这个属性很重要
     //标题栏的options比较多,有兴趣的朋友可以到VST.HEADER里面去逐个试验
     Options:=[hoColumnResize, hoDrag, hoShowSortGlyphs, hoHeaderClickAutoSort, hoAutoColumnPopupMenu];
     //让标题栏可见,并设置标题栏的基础属性
     Options:=Options+[hoVisible];
     //如果确实没有创建column,这一行可以不要
     Columns.Clear;
     //设置标题栏的字体及高度
     Font.Name:='宋体';
     Font.Size:=14;
     Height:=33;
     //创建6个column,用于分别显示不同的信息
     with Columns.Add  do
     begin
       Width:=180;
       text:='四字码';
       Hint:='机场ICAO四字码';
     end;
     with Columns.Add  do
     begin
       Width:=80;
       text:='三字码';
     end;
     with Columns.Add  do
     begin
       Width:=80;
       text:='类型';
     end;
     with Columns.Add  do
     begin
       Width:=180;
       text:='名称';
     end;
     with Columns.Add  do
     begin
       Width:=80;
       text:='跑道数';
     end;
     with Columns.Add  do
     begin
       Width:=80;
       text:='主/备';
     end;
   end;
   with vst.TreeOptions do
  begin
    SelectionOptions:=SelectionOptions+[toMultiSelect];
  end;
   with vst.TreeOptions do
   begin
      //设置autoiotions
      AutoOptions:=AutoOptions+[toAutoExpand,//点击带子节点的节点时,自动展开子节点
                                toAutoHideButtons];//当节点的所有子节点都不可见时,隐藏节点的“+”按钮
      MiscOptions:=MiscOptions+[toCheckSupport,//支持复选框
                                toEditable,//可以编辑
                                toFullRowDrag,//拖动时整行拖动
                                toNodeHeightResize//可以修改节点高度
                                ];
      SelectionOptions:=SelectionOptions+[toMultiSelect];//设置为允许多选
   end;
   createvst;

   //vst.FullExpand();
   //caption:=vst.AbsoluteIndex(vst.GetLast()).ToString();
   //也可不调用createvst,写代码如下也可创建VST
   {QRY1.First;
   while not QRY1.Eof do
   begin
     nd:=vst.AddChild(nil);
     with pcodes(vst.GetNodeData(nd))^ do
     begin
       //根节点的获取数据语句
       qry2.Open('相关的SQL语句');
       while not QRY2.Eof do
       begin
         with pcodes(vst.GetNodeData(vst.AddChild(nd)))^ do
         begin
           //获取机场数据的语句
         end;
         QRY2.Next;
       end;
     end;
     QRY1.Next;
   end; }

end;

procedure TForm2.createvst;
begin
   QRY1.Open('select * from codes where site_code in '+
             '(select distinct fir_code from codes where single_runway_ad>-1 )'+
             ' and single_runway_ad=-1');
   //firedac默认初始只读取50行数据,此函数强制让QRY1完全读取table数据
   //如果不执行此行,则recordcount将最大只有50;
   QRY1.FetchAll;
   //设置根节点数为有机场的情报区数,因为根节点指向的是情报区。
   vst.RootNodeCount:=qry1.RecordCount;
   QRY1.Close;
end;

这段代码只在第一次运行时进行,就不再一一累述了。

CODES.CSV的内容如下:

 

除了标题栏,我们也要对VST本身进行一些设置。但不会在这里细讲,而在具体章节时才予以讲述,下面让我们一步一步的来完成我们的程序吧。

posted @ 2020-05-29 14:08  Luo大哥  阅读(540)  评论(0编辑  收藏  举报