virtualtree 的使用(Delphi)

VirtualTreeview的強大,毋庸置疑,不過,你能給演示演示,也不錯,就是剛下來,只有一個可執行程序,感受像病毒。

最近比較忙,沒有上網,如今把我研究的結果和你們通報下,方便新手學習,避免走彎路和浪費時間。

我用到的功能粗略的研究了下,如下是我測試的結果,可能和高手的結果不一樣,請不要鄙視。

首先說一下速度問題,只有一列數字分組或者不分組,都很快,可是,我用的是十幾個字段,而且好幾個字段是不少漢字的,一共有 5 萬多條記錄。若是用 OnIniNode 事件,不分組大約 5 秒左右加載完成,分組要 50 秒,我懷疑是我分組的問題。但我都是一次把全部數據都取出來,再分的組,不知道什麼緣由,由於時間緣由,我沒有仔細分析。用傳統方法分組,大約 15 秒左右加載完成。我本身以爲能夠忍受了,沒有再改,下面是我用到的功能的代碼,點擊列頭排序我沒有用到,可是感受有用,也貼上了,代碼比較亂,有問題能夠問我,等幾天再結貼。有不正確的或者補充的功能,請帖出來。


一、數據加載,沒有分組的,須要分組,能夠本身加條件,這個主要是爲了說明怎麼用傳統方法加載數據,爲了明晰清楚,因此,只有一個字段。
(1)、設集合指針
    PFAName_Rec = ^TFAName_re;

    TFAName_re = record
        FAName: string;                 //方案名稱
(2)、開始加載
    p_tree.Clear;
    p_tree.NodeDataSize := SizeOf(TFAName_re);

    p_tree.BeginUpdate;
    RootNode := p_tree.AddChild(nil);
    Data := p_tree.GetNodeData(RootNode);
    
    while not Form_main.ADOQTest.Eof do
    begin
        if stop_thread then
            exit;

        Data.FAName := Form_main.ADOQTest.FieldByName('FAName').AsString;
        Form_main.ADOQTest.Next;
    end;
    p_tree.EndUpdate;

二、顯示事件,加載數據後,要顯示必須在這個事件中加入顯示的代碼
procedure TForm_485.FA_TreeGetText(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
    var CellText: WideString);
var
    Data            : PFAName_Rec;
begin
    Data := Sender.GetNodeData(Node);

    case Column of
        0:
            begin
                if Data^.FAName <> '' then
                    CellText := Data^.FAName;
            end;
    end;
end;

三、顯示圖標,雖然沒什麼大用,可是很美觀
procedure TForm_485.Wait_Send_TreeGetImageIndex(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
    var Ghosted: Boolean; var ImageIndex: Integer);
var
    wait_send_rec   : P_wait_send_Rec;
begin
    if Column <> 2 then
        exit;
    wait_send_rec := Sender.GetNodeData(Node);

    ImageIndex := wait_send_rec.is_send - 1;
end;

四、相鄰行不一樣顏色
procedure TForm_485.Wait_Send_TreeBeforeItemErase(Sender: TBaseVirtualTree;
    TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect;
    var ItemColor: TColor; var EraseAction: TItemEraseAction);
begin
    if Odd(Node.Index) then
    begin
        //        ItemColor := $FFEEEE;

        ItemColor := $00F7F7F7;
        EraseAction := eaColor;
    end;
end;

五、拖放,沒什麼大用的功能,某些地方頗有用,用按鈕或菜單實現同樣。
   拖放須要加載 ActiveX 單元才行,不然會報錯
(1)、  源控件事件  
procedure TForm_485.All_item_TreeMouseDown(Sender: TObject; Button:
    TMouseButton;
    Shift: TShiftState; X, Y: Integer);
begin
    if Button = mbLeft then
    begin
        if All_item_Tree.FocusedNode = nil then
            exit;
        if All_item_Tree.FocusedNode.ChildCount > 0 then
            exit;
        All_item_Tree.BeginDrag(False);
    end;
end;
(2)、目標事件1
procedure TForm_485.Wait_Send_TreeDragOver(Sender: TBaseVirtualTree;
    Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint;
    Mode: TDropMode; var Effect: Integer; var Accept: Boolean);
begin
    if (Source = All_item_Tree) or (Source = Wait_Send_Tree) or (Source =
        Often_item_Tree) or (Source = FA_Tree) then
    begin
        Accept := true;
    end;
end;
(3)、目標事件2
procedure TForm_485.Wait_Send_TreeDragDrop(Sender: TBaseVirtualTree;
    Source: TObject; DataObject: IDataObject; Formats: TFormatArray;
    Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode);
var
    Data            : PFAName_Rec;
begin
    cur_send_Meter_addr := trim(Edit8.Text);
    cur_send_Meter_count := 1;

    if (Source = All_item_Tree) then
    begin
        r(All_item_Tree);
    end;

    if (Source = Often_item_Tree) then
    begin
        r(Often_item_Tree);
    end;

    if (Source = Wait_Send_Tree) then
    begin
        move_item(Shift, Effect, Mode);
    end;

    if (Source = FA_Tree) then
    begin
        if FA_Tree.FocusedNode = nil then
            exit;

        Data := FA_Tree.GetNodeData(FA_Tree.FocusedNode);

        get_FA_item(Data.FAName, Wait_Send_Tree);
    end;
end;

六、編輯數據,這個我感受很實用
(1)、事件1
procedure TForm_485.Wait_Send_TreeEditing(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
begin
    if Column in [4..8] then
        Allowed := true;
end;
(2)、事件2
procedure TForm_485.Wait_Send_TreeDragAllowed(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
begin
    Allowed := Odd(Node.Index);
end;
(3)、事件3
procedure TForm_485.Wait_Send_TreeNewText(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Column: TColumnIndex; NewText: WideString);
var
    wait_send_rec   : P_wait_send_Rec;
    str_meter_addr  : string;
begin
    wait_send_rec := Sender.GetNodeData(Node);

    case Column of
        4:
            begin
                if trim(wait_send_rec.str_czy) = trim(NewText) then
                    exit;
                if length(trim(NewText)) <> 12 then
                    exit;

                wait_send_rec.metter_addr := NewText;

                if CheckBox3.Checked then
                begin
                    //保存到數據庫
                    post_item_mrz('BiaoDZ', wait_send_rec.GuiYBS, NewText);
                end;

            end;
     end;
end;

七、顯示提示,做用不大,有勝於無的功能
procedure TForm_485.Wait_Send_TreeGetHint(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Column: TColumnIndex;
    var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: WideString);
begin
    case Column of
        0: HintText := '第一列提示';
        2: HintText := '第三列提示';
        3: HintText := '第四列提示';
    end;
end;

八、點擊列頭排序,我的感受很是有用的功能,可是個人程序中沒有用到,因此,把我找到的代碼貼上了,供你們參考。
procedure TfrmMain.vCustomerTreeHeaderClick(Sender: TVTHeader;
  Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
if Button = mbLeft then
  with Sender do
    begin
    if SortColumn <> Column then
       SortColumn := Column;
    if SortDirection = sdAscending then
       SortDirection := sdDescending
    else SortDirection := sdAscending;
    vCustomerTree.SortTree(Column,SortDirection,true);
    // BIG NOTE ! ... the "DoInit" variable MUST be set to true,
    // otherwise you are ONLY sorting on nodes that have already
    // been initialised - this can cause some interesting sorts !
    end;
end;

九、查找數據,個人代碼比較多,看着可能不清晰,這是別人寫的例子,應該容易理解點,我在前面調用了2個方法,第一個是取消原來的選擇,第二個是收起節點,主要爲了找到節點後展開找到的節點。這個例子中沒有對找到的節點進行處理的代碼,例如,選擇找到的節點,展開找到的節點等。本身加吧,不難的。
(1)、以前的方法
    All_item_Tree.ClearSelection;
    All_item_Tree.FullCollapse();

(2)、調用方式
PNode := FindChild(Controltree,Controltree.RootNode,EMPID);
(3)、遞歸的查找方法
function FindChild(Sender: TBaseVirtualTree; hParent: PVirtualNode; EMPID: integer): PVirtualNode;
var
  llhChild: PVirtualNode;
  Data: PEntry;
begin
  Result := nil;

  llhChild := hParent.FirstChild; //獲取hParent的第一個子節點
  while Assigned(llhChild) do begin
    Data := Sender.GetNodeData(llhChild);
    if (Data.Kind = nkEmployee) and (Data.ID = EMPID) then begin
       Result := llhChild;
       Exit;
    end;

    {對llhChild節點進行處理}
    Result := FindChild(Sender, llhChild, EMPID);
    if Result <> nil then Exit;
    llhChild := llhChild.NextSibling;
  end;

end;

十、MoveTo 使用方法,能夠在不一樣的兩個樹中拖動,好像必須兩棵樹的結構一致,我只使用了在同一顆樹中移動的功能。這個方法在拖動(DragDrop)事件中調用,按 Ctrl 是複製,其餘是移動 

procedure TForm.move_item(Shift: TShiftState; var Effect: Integer; var Mode:
    TDropMode);
    procedure DetermineEffect;
    begin
        if Shift <> [] then
        begin

            if (Shift = [ssAlt]) or (Shift = [ssCtrl, ssAlt]) then
                Effect := DROPEFFECT_LINK
            else if Shift = [ssCtrl] then
                Effect := DROPEFFECT_COPY
            else
                Effect := DROPEFFECT_MOVE;
        end;
    end;

var
    Attachmode      : TVTNodeAttachMode;
    Nodes           : TNodeArray;
    i               : integer;
begin

    case Mode of
        dmAbove:
            AttachMode := amInsertBefore;
        //    dmOnNode:
        //      AttachMode := amAddChildLast;
        dmOnNode:
            AttachMode := amInsertAfter;
        dmBelow:
            AttachMode := amInsertAfter;
    else
        AttachMode := amNowhere;
    end;

    DetermineEffect;
    Nodes := Wait_Send_Tree.GetSortedSelection(True);
    if Effect = DROPEFFECT_COPY then
    begin
        for I := 0 to High(Nodes) do
            Wait_Send_Tree.CopyTo(Nodes[I], Wait_Send_Tree.DropTargetNode,
                AttachMode, False);
    end
    else
        for I := 0 to High(Nodes) do
            Wait_Send_Tree.MoveTo(Nodes[I], Wait_Send_Tree.DropTargetNode,
                AttachMode, False);

    //   Wait_Send_Tree.mo
end;node

相關文章
相關標籤/搜索