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

📄 dbtree.pas

📁 delphi编程控件
💻 PAS
📖 第 1 页 / 共 5 页
字号:
procedure DoRefreshText;
var
  i: Integer;
begin
  for i := 0 to NewTVRecordList.Count - 1 do
  begin
    with TTvRecordInfo(NewTVRecordList[i]) do
      if (TTvRecordInfo(FTVRecordList[i]).Text <> Text) then
      begin
        Node := GetIDNode(ID);
        if (Node <> nil) and (Node.Text <> Text) then
          Node.Text := Text;
      end;
  end;
end; { DoRefreshText }

procedure DoTheBuild;
begin
  if (TopItem = nil) then
    TopItemID := FRootID
  else
    TopItemID := IDOfNode(TopItem);
  SelectedItemID := SelectedID;
  StoreExpanded;
  Items.Clear;
  if Assigned(FSaveIDList) then
  begin
    FSaveIDList.Free;
    FSaveIDList := nil;
  end;
  if (PreviousSortType <> stNone) then
  { adding nodes goes much faster without sorting: }
    SortType := stNone;
  DoCreateTree; { find root and call CreateTree }
  if (PreviousSortType <> stNone) then
    SortType := PreviousSortType;
  Exclude(FState, dtvsBuilding);
  if (Items.Count = 0) then
    exit;
  ReStoreExpanded; { Expand previous expanded items }
{ Find previous TopItem: }
  Node := GetIDNode(TopItemID);
  if (Node <> nil) then
    TopItem := Node;
{ Find previous Selected: }
  if (dtSynchronizeDataSet in Options) then
  begin
  { Select current record: }
    Node := GetDataSetIDNode;
    if (Node = nil) then
    begin
    { Current record not in Items: }
      if (Selected = nil) and (TopItem <> nil) then
        Selected := TopItem;
      if (Selected <> nil) then
        SynchronizeCurrentRecordToSelectedNode;
    end
    else
      Selected := Node;
  end
  else
  begin
    if (SelectedItemID <> '') then
    begin
      Node := GetIDNode(SelectedItemID);
      if (Node = nil) then
      begin
        if (TopItem <> nil) then
          Selected := TopItem;
      end
      else
        Selected := Node;
    end
    else
      if (TopItem <> nil) then
        Selected := TopItem;
  end;
end; { DoTheBuild }

begin { BuildTree }
  FRSelected := nil;
  KillAllTimer;
  FIDOfDeleted := '';
  if not NeedRebuild then exit;
  Exclude(FState, dtvsNeedReBuild);
  PreviousSortType := SortType;
  Items.BeginUpdate; { changes are not visible until EndUpdate }
  try
    DataSet.DisableControls;
    Include(FState, dtvsBuilding);
    if (dtvsDataSetNeedsRefresh in FState) then
    begin
    {$IFDEF Ver90}
      DataSet.UpdateCursorPos;
      if (DbiForceReread(DataSet.Handle) = 0) then
        DataSet.Resync([]);
    {$ELSE DEF Ver90} { Delphi >= 3.0: }
      if (Dataset is TBDEDataSet) then
      begin
        TBDEDataSet(DataSet).UpdateCursorPos;
        if (DbiForceReread(TBDEDataSet(DataSet).Handle) = 0) then
          DataSet.Resync([]);
      end;
    {$ENDIF DEF Ver90}
      Exclude(FState, dtvsDataSetNeedsRefresh);
    end;
    NewTVRecordList := CreateTVRecordList;
    if (NewTVRecordList <> nil) then
    begin
      try
        case NewTVRecordList.GetDifference(FTVRecordList) of
          tvrldNone:
            if (Items.GetFirstNode <> nil) and
               (IDOfNode(Items.GetFirstNode) <> FRootID) then
            { RootID has changed: }
              DoTheBuild;
          tvrldText:
            DoRefreshText;
          else
            DoTheBuild;
        end; { case }
      finally
        if Assigned(FTVRecordList) then
          FTVRecordList.Free;
        FTVRecordList := NewTVRecordList;
      end;
    end;
  finally
    Include(FState, dtvsBuilding);
    DataSet.EnableControls;
    Exclude(FState, dtvsBuilding);
    Items.EndUpdate; { make changes visible }
    Node := Selected;
    if (Node <> nil) then
    begin
      Node.MakeVisible;
      if (dtvsEditAfterReBuild in FState) then
        Node.EditText;
    end;
    Exclude(FState, dtvsEditAfterReBuild);
  end;
end;

function TCustomDBTreeView.NeedRebuild: Boolean;
begin
{ Function BuildTree produce some side effects by changing
  following properties, fields:
  1. DataSet's current record;
  2. Table.IndexFieldNames;
  3. Table.State -> dsBrowse;
  4. Table's buffer for searching;
  There are no ways retain and later restore State
  and search buffer(without using private methods).
  Therefore Building method is called only in Browse state,
  and when not used GoToKey method. }
  Result := false;
  if (FTableIDField = '') or (FTableTextField = '') or
     (csLoading in ComponentState) or (DataSet = nil) then
    exit;
  with DataSet do
  begin
    FPrevState := State;
    if (dtvsBuilding in FState) or (FDisableCount > 0) then
      exit;
    if State = dsBrowse then
      Result := true;
    if (FPrevState = dsSetKey) and (State = dsBrowse) then
      Result := false; { Catch calls of GoToKey method }
  end;
end;

procedure TCustomDBTreeView.CreateTree(ParentNode: TTreeNode;
  const AParent: string; TempRecordList: TTVRecordList);
var
  Node: TTreeNode;
  Index: Integer;
begin
  if TempRecordList.FindParent(AParent, Index) then
  begin
    with TempRecordList.Parent[Index] do
    begin
      if (ID = FRootID) or (ID = AParent) then
      begin
        ClosedLoop;
        exit;
      end;
      Node := Items.AddChild(ParentNode, Text);
      TTreeIDNode(Node).ID := ID;
      CreateTree(Node, ID, TempRecordList);
    end;
    Inc(Index);
    while (Index < TempRecordList.Count) do
    begin
      with TempRecordList.Parent[Index] do
      begin
        if (Parent <> AParent) then
          break;
        if (ID = FRootID) or (ID = AParent) then
          ClosedLoop
        else
        begin
          Node := Items.Add(Node, Text);
          TTreeIDNode(Node).ID := ID;
          CreateTree(Node, ID, TempRecordList);
        end;
      end;
      Inc(Index);
    end;
  end;
end;

procedure TCustomDBTreeView.BuildTreeIfNeeded;
begin
  if (dtvsNeedReBuild in FState) and (FDisableCount = 0) and
     (not (dtvsBuilding in FState)) and
     (DataSet.State = dsBrowse) and
     (FIDOfDeleted = '') and
     ((not (dtRebuildFocusedOnly in Options)) or Focused) then
    BuildTree;
end;

procedure TCustomDBTreeView.ClosedLoop;
begin
  if Assigned(FOnClosedLoop) then
    FOnClosedLoop(Self);
end;

procedure TCustomDBTreeView.RootNotFound;
begin
{ if (csDesigning in ComponentState) then
    ShowMessage('No record with root-ID (' + FRootID + ') found.'); {}
  if Assigned(FOnRootNotFound) then
    FOnRootNotFound(Self);
end;

function TCustomDBTreeView.AddNewNodeFromDataset(
  Node: TTreeNode; AsChild: Boolean): TTreeNode;
begin
  with DataSet do
  begin
    if not AsChild or (Node = nil) then
      Result := Items.Add(Node, FieldByName(FTableTextField).AsString)
    else
      Result := Items.AddChild(Node, FieldByName(FTableTextField).AsString);
    if (Result <> nil) then
      TTreeIDNode(Result).ID := FieldByName(FTableIDField).AsString;
  end;
end;

function TCustomDBTreeView.GetIDNode(const aID: string): TTreeNode;
var
  i: Integer;
begin
  for i := 0 to Items.Count -1 do
  begin
    Result := TTreeNode(Items[i]);
    if (IDOfNode(Result) = aID) then
      exit;
  end;
  Result := nil
end;

function TCustomDBTreeView.GetDataSetIDNode: TTreeNode;
begin
  Result := GetIDNode(DataSet.FieldByName(FTableIDField).AsString);
end;

procedure TCustomDBTreeView.DataChanged;
begin
  if (dtvsChangingDataset in FState) or (dtvsBuilding in FState) then
  { TCustomDBTreeView has changed Dataset, do nothing: }
    Exclude(FState, dtvsChangingDataset)
  else
    RecordNumberChanged;
end;

procedure TCustomDBTreeView.DatasetRefreshed;
begin
  Include(FState, dtvsNeedReBuild);
  Include(FState, dtvsDataSetNeedsRefresh);
  if (FReBuildTimer = 0) and
     (Focused or not (dtRebuildFocusedOnly in Options)) then
    FReBuildTimer := SetTimer(Handle, TimerIDRebuild, RebuildTickCount, nil);
end;

procedure TCustomDBTreeView.RecordNumberChanged;
begin
  if (FDisableCount = 0) and (not (dtvsBuilding in FState)) and
     (not IsEditing) and (FIDOfDeleted = '') then
    if (dtvsNeedReBuild in FState) and
       ((not (dtRebuildFocusedOnly in Options)) or Focused) then
      BuildTree
    else
      if (dtSynchronizeDataSet in Options) then
        SynchronizeSelectedNodeToCurrentRecord
end;

procedure TCustomDBTreeView.RecordChanged(Field: TField);
var
  Node: TTreeNode;
  FieldName: string;
begin
  if (FDisableCount = 0) and not (dtvsBuilding in FState) and
     (Field <> nil) then
  begin
    FieldName := UpperCase(Field.FieldName);
    if (FieldName = UpperCase(FTableTextField)) then
    begin
      Node := GetDataSetIDNode;
      if Node <> nil then
      begin
        Include(FState, dtvsChangingDataset);
        Node.Text := DataSet.FieldByName(FTableTextField).AsString;
      end;
    end
    else
      if (FieldName = UpperCase(FTableParentField)) or
         (FieldName = UpperCase(FTableIDField)) or
         ((DataSet is TTable) and
          (Pos(FieldName, UpperCase(TTable(DataSet).MasterFields)) > 0)) or
         (DataSet.Filtered and
          (Pos(FieldName, UpperCase(DataSet.Filter)) > 0)) then
      begin
      { maybe structure of tree changed: }
        if (DataSet.State = dsEdit) or (DataSet.State = dsInsert) then
          Include(FState, dtvsNeedReBuildAfterPost)
        else
          if (not (dtRebuildFocusedOnly in Options)) or Focused then
            BuildTree
          else
            Include(FState, dtvsNeedReBuild);
      end;
  end;
end;

procedure TCustomDBTreeView.EditingChanged;
var
  WasFocused: Boolean;
begin
  if (DataSet.State = dsEdit) then
  begin
    if (FDisableCount = 0) and not ReadOnly and not IsEditing then
    begin
    { DataSet.State has changed from dsEdit to dsBrowse, but that was not
      done by TCustomDBTreeView: }
      if (dtFocusOnEdit in Options) then
        SetFocus;
      if Focused then
      begin
      { TCustomDBTreeView is Focused: Set selected node to edit-mode: }
        if not (dtSynchronizeDataSet in Options) then
          SynchronizeSelectedNodeToCurrentRecord;
        if (Selected <> nil) then
          Selected.EditText;
      end;
    end;
    Include(FState, dtvsDatasetInEditMode);
  end
  else
    if (DataSet.State = dsInsert) then
    begin
      if (FDisableCount = 0) and not ReadOnly then
      begin
      { DataSet was set by someone (not by us) to insert-mode: }
        WasFocused := Focused;
        Inc(FDisableCount); { avoid BuildTree at next action: }
        DataSet.Cancel;     { Cancel insert-mode, because... }
        Insert(dtInsertAsChild in Options); { ... we will do it our way! }
        if (not WasFocused) then
        begin
          if (dtFocusOnEdit in Options) then
            SetFocus
          else
          begin
          { We don't have the focus, do not edit node: }
            if (Selected <> nil) then
              Selected.EndEdit(false);
          { If we get the focus later, please edit node: }
            Include(FState, dtvsLostFocusWhileDatasetInEditModes);
          end;
        end;
        Dec(FDisableCount);
      end;
      Include(FState, dtvsDatasetInInsertMode);
    end;
end;

procedure TCustomDBTreeView.DataSetBeforePost;
begin
  if (dtvsDatasetInEditMode in FState) then
  begin
  { DataSet.State has changed from dsEdit to dsBrowse, but that was not
    done by TCustomDBTreeView: }
    Exclude(FState, dtvsDatasetInEditMode);
    if (FDisableCount = 0) and IsEditing then
    begin
    { TCustomDBTreeView is still in edit-mode but someone posted e.g.
      by pressing post on a DBNavigator. End edit: }
      Inc(FDisableCount);
      with Selected do
      begin
        EndEdit(false);
        if (DataSet.FieldByName(FTableTextField).AsString <> Text) then
          DataSet.FieldByName(FTableTextField).AsString := Text;
      end;
      Dec(FDisableCount);
    end;
  end
  else
  begin
    if (dtvsDatasetInInsertMode in FState) then
    begin
    { DataSet.State has changed from dsInsert to dsBrowse, but that was
      not done by TCustomDBTreeView: }
      Exclude(FState, dtvsDatasetInInsertMode);
      if (FDisableCount = 0) then
      begin
        if IsEditing then
        begin
        { TCustomDBTreeView is still in insert-mode but someone posted
          e.g. by pressing post on a DBNavigator. End insert: }
          Inc(FDisableCount);
          with Selected do
          begin
            EndEdit(false);
            if (DataSet.FieldByName(FTableTextField).AsString <> Text) then
              DataSet.FieldByName(FTableTextField).AsString := Text;
          end;
          Dec(FDisableCount);
        end
        else
        begin
        { insert-mode was not done by us.
          Structure of tree has changed: }
          Include(FState, dtvsNeedReBuildAfterPost);
        end;
      end;
    end;
  end;
  Exclude(FState, dtvsLostFocusWhileDatasetInEditModes);
end;

procedure TCustomDBTreeView.DataSetAfterPost;
begin
  if (dtvsNeedReBuildAfterPost in FState) then

⌨️ 快捷键说明

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