⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 treevwex.pas

📁 delphi编程控件
💻 PAS
📖 第 1 页 / 共 3 页
字号:
    result := CanEdit(Node);
  if result and Node.HasChildren then
    for i := 0 to Node.Count - 1 do
    begin
      result := CanDelete(Node.Item[i]);
      if not result then
        exit;
    end;
end;

function TCustomTreeViewEx.DoDelete(Node: TTreeNode): Boolean;
begin
  Items.Delete(Node);
  result := true;
end;

function TCustomTreeViewEx.GetDeleteQuestion(Node: TTreeNode): string;
begin
  if (Node <> nil) and (Pos('%s', stveDefaultDeleteQuestion) > 0) then
    result := Format(stveDefaultDeleteQuestion, [Node.Text])
  else
    result := stveDefaultDeleteQuestion;
end;

function TCustomTreeViewEx.ShowDeletePrompt(Node: TTreeNode;
  var DeleteAll: Boolean; ShowDeleteAllButton: Boolean): Boolean;
const
  mb: array[boolean] of TMsgDlgButtons =
    ([mbOK, mbCancel], [mbOK, mbCancel, mbAll]);
var
  Msg: Integer;
begin
  Result := DeleteAll or not (tveConfirmDelete in Options);
  if Result then
    DeleteAll := true
  else
  begin
    Msg := MessageDlg(GetDeleteQuestion(Node),
                      mtConfirmation, mb[ShowDeleteAllButton], 0);
    if (Msg = mrOk) then
      Result := true
    else
      if (Msg = mrAll) then
      begin
        Result := true;
        DeleteAll := true;
      end;
  end;
end;

procedure TCustomTreeViewEx.InternalDeleteNode(Node: TTreeNode;
  AskForDeleteAll: Boolean; var DeleteAll, Canceled: Boolean);
var
  i: Integer;
  OldSelected: TTreeNode;
  NewSelected: TTreeNode;
begin
  if Canceled or (Node = nil) then
    exit;
  if Node.HasChildren then
    for i := Node.Count - 1 downto 0 do
    begin
      InternalDeleteNode(Node.Item[i], AskForDeleteAll, DeleteAll, Canceled);
      if Canceled then
        exit;
    end;
  if (Node = Selected) then
  begin
    if (Node.GetNextSibling <> nil) then
      NewSelected := Node.GetNextSibling
    else
      if (Node.GetPrevSibling <> nil) then
        NewSelected := Node.GetPrevSibling
      else
        if (Node.Parent <> nil) then
          NewSelected := Node.Parent
        else
          NewSelected := nil;
  end
  else
    NewSelected := Selected;
  OldSelected := Selected;
  Selected := Node;
  Canceled := not ShowDeletePrompt(Node, DeleteAll, AskForDeleteAll);
  if not Canceled then
  begin
    DoDelete(Node);
    if (NewSelected <> nil) then
      Selected := NewSelected;
  end
  else
    if (OldSelected <> nil) then
      Selected := OldSelected;
end;

procedure TCustomTreeViewEx.DeleteNode(Node: TTreeNode);
var
  AskForDeleteAll: Boolean;
  DeleteAll: Boolean;
  Canceled: Boolean;
begin
  if not CanDelete(Node) then
    exit;
  AskForDeleteAll := Node.HasChildren;
  DeleteAll := false;
  Canceled := false;
  InternalDeleteNode(Node, AskForDeleteAll, DeleteAll, Canceled);
end;

function TCustomTreeViewEx.CanEdit(Node: TTreeNode): Boolean;
begin
  KillAllTimer;
  if ReadOnly or ((tveRootItemReadOnly in Options) and IsRootNode(Node)) then
    Result := false
  else
    Result := inherited CanEdit(Node);
end;

function TCustomTreeViewEx.DragAllowed(Node: TTreeNode): Boolean;
begin
  Inc(FDisableCount);
  try
    result := CanEdit(Node) and not IsSingleRootNode(Node);
  finally
    Dec(FDisableCount);
  end;
end;

{$HINTS OFF}
procedure TCustomTreeViewEx.Insert(AsChild: Boolean);
var
  NewNode: TTreeNode;
begin
  KillAllTimer;
  Inc(FDisableCount);
  try
    if AsChild and (Selected <> nil) then
      NewNode := Items.AddChild(Selected, '')
    else
      NewNode := Items.Insert(Selected, '');
    if (NewNode <> nil) then
    begin
      if Focused then
        NewNode.EditText;
    end;
  finally
    Dec(FDisableCount);
  end;
end;
{$HINTS ON}

procedure TCustomTreeViewEx.Delete;
begin
  KillAllTimer;
  DeleteNode(Selected);
end;

procedure TCustomTreeViewEx.KeyDown(var Key: Word; Shift: TShiftState);
begin
  KillAllTimer;
  inherited KeyDown(Key, Shift);
  case Key of
    VK_INSERT:
      if (tveAllowInsert in Options) and (not IsEditing) and
         (not ReadOnly) then
      begin
        if (tveInsertAsChild in Options) then
          Insert(true)
        else
          Insert((ssShift in Shift) or (ssCtrl in Shift));
        Key := 0;
      end;
    VK_DELETE:
      if (tveAllowDelete in Options) and (not IsEditing) and
         (not ReadOnly) then
      begin
        Delete;
        Key := 0;
      end;
  end;
end;

procedure TCustomTreeViewEx.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  HT: THitTests;
begin
  if (ssDouble in Shift) then
  begin
    if (FMouseSelectTimer <> 0) then
    begin
      KillTimer(Handle, TimerIDMouseSelect);
      FMouseSelectTimer := 0;
    end;
    Include(FState, tvesMouseStillDownAfterDoubleClick);
    inherited;
    exit;
  end;
  if (Button = mbLeft) then
    FLMouseDownTickCount := GetTickCount;
  inherited;
  if (Button = mbLeft) then
  begin
      if (not Dragging) and (Selected <> nil) and
         (GetNodeAt(X, Y) = Selected) then
      begin
        if (tveAutoDragMove in Options) and DragAllowed(Selected) then
          BeginDrag(False);
        if Assigned(FOnMouseSelect) and
           (not (tveMouseMoveSelect in FOptions)) and
           (not (ssDouble in Shift)) then
        begin
          HT := GetHitTestInfoAt(X, Y);
          if (HT - [htOnItem {, htOnIcon, htOnIndent, htOnRight}] <> HT) then
          begin
            if not Selected.HasChildren then
              FOnMouseSelect(self)
            else
            { maybe it becomes a doubleclick, wait a little bit: }
              if (FMouseSelectTimer = 0) then
                FMouseSelectTimer :=
                  SetTimer(Handle, TimerIDMouseSelect,
                    GetDoubleClickTime - (GetTickCount - FLMouseDownTickCount),
                    nil);
          end;
        end;
      end;
  end;
end;

procedure TCustomTreeViewEx.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  Node: TTreeNode;
  XInClientRect, YInClientRect: Integer;
function NodeLineFullVisible(Node: TTreeNode): Boolean;
var
  NodeRect: TRect;
begin
  NodeRect := Node.DisplayRect(false);
  result := (NodeRect.Top >= 0) and (NodeRect.Bottom <= ClientHeight);
end;
begin
  inherited MouseMove(Shift, X, Y);
  if (tveMouseMoveSelect in FOptions) or Dragging then
  begin
    if (ssLeft in Shift) then
    begin
      if (Y < 1) then
        YInClientRect := 1
      else
        if (Y >= ClientHeight) then
          YInClientRect := ClientHeight - 1
        else
          YInClientRect := Y;
      if (X < 1) then
        XInClientRect := 1
      else
        if (X >= ClientWidth) then
          XInClientRect := ClientWidth - 1
        else
          XInClientRect := X;
      Node := GetNodeAt(XInClientRect, YInClientRect);
      if (Node <> nil) then
      begin
        DoScroll(Node, X, Y);
        try
          Node := GetNodeAt(XInClientRect, YInClientRect);
        except
          Node := nil;
        end;
      end;
    end
    else
      Node := GetNodeAt(X, Y);
    if (Node <> nil) and NodeLineFullVisible(Node) then
    begin
      Node.MakeVisible;
      if not Dragging then
        Selected := Node;
    end;
  end;
end;

procedure TCustomTreeViewEx.MouseUp(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
var
  HT: THitTests;
  DeltaMouseDownTickCount: Integer;

procedure StartMouseSelect;
begin
  if not Selected.HasChildren then
    FOnMouseSelect(self)
  else
  { maybe it becomes a doubleclick, wait a little bit: }
    if (FMouseSelectTimer = 0) then
      FMouseSelectTimer :=
        SetTimer(Handle, TimerIDMouseSelect,
                 GetDoubleClickTime - DeltaMouseDownTickCount, nil);
end;

begin { MouseUp }
  if (FScrollTimer <> 0) then
  begin
    KillTimer(Handle, TimerIDScroll);
    FScrollTimer := 0;
  end;
  inherited MouseUp(Button, Shift, X, Y);
  if (tvesMouseStillDownAfterDoubleClick in FState) then
    Exclude(FState, tvesMouseStillDownAfterDoubleClick)
  else
  begin
      if (Button = mbLeft) then
      begin
        if (not Dragging) and (Selected <> nil) and
           (GetNodeAt(X, Y) = Selected) then
        begin
          DeltaMouseDownTickCount := (GetTickCount - FLMouseDownTickCount);
          if (DeltaMouseDownTickCount < GetDoubleClickTime) and
             Assigned(FOnMouseSelect) then
          begin
            HT := GetHitTestInfoAt(X, Y);
            if (tveMouseMoveSelect in FOptions) then
            begin
            { MouseSelect if not hit on Icon or Indent: }
              if (HT - [htOnItem {, htOnIcon, htOnIndent}, htOnRight] <>
                  HT) then
                StartMouseSelect;
            end
            else
            begin
            { MouseSelect on direct hit only: }
              if (HT - [htOnItem {, htOnIcon, htOnIndent, htOnRight}] <>
                  HT) then
                StartMouseSelect;
            end;
          end;
        end;
      end;
  end;
end;

procedure TCustomTreeViewEx.WMTimer(var Msg: TWMTimer);
var
  Node: TTreeNode;
  P: TPoint;
begin
  case Msg.TimerID of
    TimerIDScroll:
      begin
        KillTimer(Handle, TimerIDScroll);
        FScrollTimer := 0;
        GetCursorPos(P);
        with ScreenToClient(P) do
        begin
          if (Y < 1) then
            Y := 1
          else
            if (Y >= ClientHeight) then
              Y := ClientHeight - 1;
          if (X < 1) then
            X := 1
          else
            if (X >= ClientWidth) then
              X := ClientWidth - 1;
          Node := GetNodeAt(X, Y);
          if (Node <> nil) then
          begin
            with ScreenToClient(P) do
              DoScroll(Node, X, Y);
            if (tveMouseMoveSelect in FOptions) or Dragging then
            begin
              Node := GetNodeAt(X, Y);
              if (Node <> nil) then
              begin
                Node.MakeVisible;
                if (tveMouseMoveSelect in FOptions) then
                  Selected := Node;
              end;
            end;
          end;
        end;
      end;
    TimerIDMouseSelect:
      begin
        KillTimer(Handle, TimerIDMouseSelect);
        FMouseSelectTimer := 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -