📄 dbtree.pas
字号:
begin
Exclude(FState, dtvsNeedReBuildAfterPost);
if (not (dtRebuildFocusedOnly in Options)) or Focused then
BuildTree
else
Include(FState, dtvsNeedReBuild);
end;
end;
procedure TCustomDBTreeView.DataSetAfterCancel;
var
Node: TTreeNode;
begin
Exclude(FState, dtvsNeedReBuildAfterPost);
if (dtvsLostFocusWhileDatasetInEditModes in FState) then
begin
if (Selected <> nil) and not IsEditing then
begin
{ Maybe we changed the Text of the node, but that was cancelled now: }
Selected.Text := DataSet.FieldByName(FTableTextField).AsString;
end;
Exclude(FState, dtvsLostFocusWhileDatasetInEditModes);
end;
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
{ TCustomDBTreeView is still in edit-mode but someone canceled e.g.
by pressing cancel on a DBNavigator. Stop edit: }
Selected.EndEdit(true);
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
{ Someone canceled inserting, e.g. by pressing cancel on a DBNavigator,
or a TDBGrid with dgCancelOnExit in Options lost focus: }
if IsEditing then
begin
{ still in insert-mode. Stop insert: }
Node := Selected;
if (Node <> nil) then
begin
Node.EndEdit(true);
if (Node.GetNextSibling <> nil) then
Selected := Node.GetNextSibling
else
if (Node.GetPrevSibling <> nil) then
Selected := Node.GetPrevSibling
else
if (Node.Parent <> nil) then
Selected := Node.Parent;
Items.Delete(Node);
end;
end
else
begin
{ Maybe TDBGrid with dgCancelOnExit in Options lost focus and the
empty record was deleted. }
{ if (DataSet.FieldByName(FTableIDField).AsString <> SelectedID) ...
does not work because RecordNumberChanged happend already. So: }
if Assigned(FTVRecordList) then
begin
{ sorry, but we have to do a complete rebuild: }
FTVRecordList.Free;
FTVRecordList := nil;
end;
BuildTree;
end;
end;
end;
end;
end;
procedure TCustomDBTreeView.DataSetBeforeDelete;
var
Node: TTreeNode;
begin
if (FDisableCount = 0) and (not Readonly) then
begin
Node := GetDataSetIDNode;
if (Node <> nil) then
begin
if (dtRootItemReadOnly in Options) and IsRootNode(Node) then
{ Do not let the user delete a RootNode if dtRootItemReadOnly in Options.
The EAbort exception is Delphi's "silent" exception.
When it is raised, no message box appears to inform the user: }
raise EAbort.Create('RootItem is ReadOnly');
if (dtConfirmDelete in Options) or Node.HasChildren then
begin
DeleteNode(Node); { ask user }
{ Raise the EAbort exception, Delphi's "silent" exception, to stop
deletion of a record that does not exist anymore: }
raise EAbort.Create(''); { exit dataset.delete }
{ Sorry, EAbort is not "silent" in the IDE, press F9 to continue... }
end;
end
else
{ record is not in tree: }
if (dtConfirmDelete in Options) then
{ No confirmation possible: }
raise EAbort.Create(''); { exit dataset.delete }
end;
{ No reason to abort deletion or do it ous way: }
if (FDisableCount = 0) then
try
FIDOfDeleted := Dataset.FieldByName(FTableIDField).AsString;
except
FIDOfDeleted := '';
end;
end;
procedure TCustomDBTreeView.DataSetAfterDelete;
var
Node: TTreeNode;
begin
if (FDisableCount = 0) then
if (FIDOfDeleted <> '') then
begin
Node := Selected;
if (Node.GetNextSibling <> nil) then
Selected := Node.GetNextSibling
else
if (Node.GetPrevSibling <> nil) then
Selected := Node.GetPrevSibling
else
if (Node.Parent <> nil) then
Selected := Node.Parent;
Items.Delete(Node);
FIDOfDeleted := '';
end
else
if (not (dtRebuildFocusedOnly in Options)) or Focused then
BuildTree
else
Include(FState, dtvsNeedReBuild);
end;
function TCustomDBTreeView.DataSetLocate(const ID: string): Boolean;
begin
with DataSet do
begin
if (ID = FieldByName(FTableIDField).AsString) then
begin
Result := true;
exit; { nothing to do }
end;
if (ID = '') then
begin
Result := false;
exit; { DataSet.Locate does not work with empty value }
end;
Include(FState, dtvsChangingDataset);
Inc(FDisableCount);
try
Result := DataSet.Locate(FTableIDField, ID, []);
finally
Dec(FDisableCount);
end;
end;
end;
procedure TCustomDBTreeView.SynchronizeSelectedNodeToCurrentRecord;
var
Node: TTreeNode;
begin
Node := GetDataSetIDNode;
if (Node <> nil) then
begin
Selected := Node;
Node.MakeVisible;
if (dtAutoExpand in Options) and Node.HasChildren then
begin
try
Inc(FDisableCount);
Node.Expand(dtAutoExpand in Options);
Selected := Node;
finally
Dec(FDisableCount);
end;
end;
end;
end;
procedure TCustomDBTreeView.SynchronizeCurrentRecordToSelectedNode;
begin
if (Selected <> nil) and (DataSet <> nil) and (DataSet.Active) then
DataSetLocate(SelectedID);
end;
procedure TCustomDBTreeView.IndexChanged;
begin
if (not (dtvsBuilding in FState)) and (FDisableCount = 0) and
(dtSynchronizeDataSet in Options) then
SynchronizeCurrentRecordToSelectedNode;
end;
procedure TCustomDBTreeView.Expand(Node: TTreeNode);
begin
inherited Expand(Node);
{
if (not (dtvsBuilding in FState)) and (FDisableCount = 0) and
(Selected <> nil) then
Selected.MakeVisible;
}
end;
procedure TCustomDBTreeView.SetRootID(ID: string);
begin
if (FRootID <> ID) then
begin
FRootID := ID;
if FTreeViewLink.Active then
BuildTree;
end;
end;
function TCustomDBTreeView.GetID(AIndex: Integer): string;
begin
Result := '';
if (AIndex >= 0) and (AIndex < Items.Count) then
Result := IDOfNode(Items[AIndex]);
end;
function TCustomDBTreeView.GetSelectedID: string;
begin
if Selected = nil then
Result := FRootID
else
Result := IDOfNode(Selected);
end;
procedure TCustomDBTreeView.SelectID(const Value: string);
var
Node: TTreeNode;
begin
Node := GetIDNode(Value);
if (Node <> nil) then
Selected := Node;
end;
procedure TCustomDBTreeView.CNNotify(var Message: TWMNotify);
begin
if (Message.NMHdr^.code = TVN_BEGINLABELEDIT) then
begin
inherited;
if (DataSet = nil) then
exit;
if (Message.Result = 0) and (DataSet <> nil) then
begin { node is in edit-mode now: }
try
if (DataSet.State = dsBrowse) then
begin
if not (dtSynchronizeDataSet in Options) then
SynchronizeCurrentRecordToSelectedNode; { Synchronize now }
if (dtvsNeedReBuild in FState) then
begin
Message.Result := 1;
Include(FState, dtvsEditAfterReBuild);
DatasetRefreshed;
end
else
begin
Inc(FDisableCount);
try
DataSet.Edit;
if (dtvsNeedReBuild in FState) then
begin
DataSet.Cancel;
Message.Result := 1;
Include(FState, dtvsEditAfterReBuild);
DatasetRefreshed;
end;
finally
Dec(FDisableCount);
end;
end;
end;
except
Message.Result := 1;
raise;
end;
end;
end
else
inherited;
end;
function TCustomDBTreeView.CanEdit(Node: TTreeNode): Boolean;
begin
KillAllTimer;
if DataSet.CanModify then
Result := inherited CanEdit(Node)
else
Result := false;
end;
procedure TCustomDBTreeView.AfterEdit(Sender: TObject;
Node: TTreeNode; var S: string);
begin
if Assigned(FUserOnEdited) then
FUserOnEdited(Sender, Node, S);
if (FDisableCount = 0) and (Node <> nil) then
begin
with DataSet do
begin
if (State <> dsInsert) and (State <> dsEdit) then
exit;
if (FieldByName(FTableIDField).AsString <> IDOfNode(Node)) then
exit; { maybe an error: this is not the record we started to edit! }
Inc(FDisableCount);
try
if (FieldByName(FTableTextField).AsString <> S) then
FieldByName(FTableTextField).AsString := S;
if Focused then { if we just lost focus, don't touch DataSet }
begin
Post;
end;
finally
Dec(FDisableCount);
end;
end;
end;
end;
procedure TCustomDBTreeView.Edit(const Item: TTVItem);
var
DeleteAll: Boolean;
Canceled: Boolean;
begin
if Assigned(FUserOnEdited) then
exit; { rekursive call }
FUserOnEdited := OnEdited;
OnEdited := AfterEdit;
try
inherited Edit(Item); { calls proc AfterEdit if something was changed }
finally
OnEdited := FUserOnEdited;
FUserOnEdited := nil;
end;
if (FDisableCount > 0) then
exit;
if (DataSet = nil) then
exit;
if not Focused then
begin
{ we just lost the focus: }
if (dtCancelOnExit in Options) and (DataSet.State = dsInsert) then
begin
if not DataSet.Modified then
begin
Exclude(FState, dtvsDatasetInEditMode);
Exclude(FState, dtvsDatasetInInsertMode);
DeleteAll := true;
Canceled := false;
InternalDeleteNode(Selected, false, DeleteAll, Canceled);
exit;
end;
end;
Include(FState, dtvsLostFocusWhileDatasetInEditModes);
exit;
end;
Exclude(FState, dtvsDatasetInEditMode);
Exclude(FState, dtvsDatasetInInsertMode);
if (DataSet.State = dsInsert) then
begin
{ proc AfterEdit was not called: user cancelled inserting }
DeleteAll := true;
Canceled := false;
InternalDeleteNode(Selected, false, DeleteAll, Canceled);
end
else
if (DataSet.State = dsEdit) then
begin
{ proc AfterEdit was not called: user cancelled editing }
Inc(FDisableCount);
try
DataSet.Cancel;
finally
Dec(FDisableCount);
end;
end;
end;
procedure TCustomDBTreeView.Change(Node: TTreeNode);
begin
if (FDisableCount = 0) then
begin
FTreeViewLink.CheckRefresh;
if (dtvsNeedReBuild in FState) then
BuildTree;
end;
IndexChanged;
inherited Change(Node);
end;
procedure TCustomDBTreeView.SetOptions(Value: TDBTreeOptions);
var
TreeViewExOptions: TTreeViewExOptions;
begin
if (dtSynchronizeDataSet in Value) and
not (dtSynchronizeDataSet in Options) then
SynchronizeCurrentRecordToSelectedNode; { Synchronize now }
TreeViewExOptions := [];
if (dtAllowDelete in Value) then
Include(TreeViewExOptions, tveAllowDelete);
if (dtAllowInsert in Value) then
Include(TreeViewExOptions, tveAllowInsert);
if (dtAutoDragMove in Value) then
Include(TreeViewExOptions, tveAutoDragMove);
if (dtRootItemReadOnly in Value) then
Include(TreeViewExOptions, tveRootItemReadOnly);
if (dtConfirmDelete in Value) then
Include(TreeViewExOptions, tveConfirmDelete);
if (dtMouseMoveSelect in Value) then
Include(TreeViewExOptions, tveMouseMoveSelect);
if (dtInsertAsChild in Value) then
Include(TreeViewExOptions, tveInsertAsChild);
if (FRootID = '') then
Include(TreeViewExOptions, tveMultipleRootsAllowed);
inherited Options := TreeViewExOptions;
FOptions := Value;
end;
function TCustomDBTreeView.DragAllowed(Node: TTreeNode): Boolean;
begin
if (DataSet <> nil) and not DataSet.CanModify then
result := false
else
result := inherited DragAllowed(Node);
end;
function TCustomDBTreeView.GetNewID: string;
var
FIndexName: string;
FIndexFields: string;
sID: string;
IntValue: Integer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -