📄 jvdbtreeview.pas
字号:
AddRecord;
Next;
end;
{###}
finally
GotoBookmark(BK);
FreeBookmark(BK);
EnableControls;
end;
end;
finally
Items.EndUpdate;
InTreeUpdate := False;
end;
end;
procedure TJvCustomDBTreeView.InternalDataChanged;
begin
if not HandleAllocated or UpdateLocked or InDataScrolled then
Exit;
// InDataScrolled := True;
try
DataChanged;
finally
// InDataScrolled := False;
end;
end;
procedure TJvCustomDBTreeView.DataChanged;
var
RecCount: Integer;
begin
case FDataLink.DataSet.State of
dsBrowse:
begin
RecCount := FDataLink.DataSet.RecordCount;
if (RecCount = -1) or (RecCount <> OldRecCount) then
UpdateTree;
OldRecCount := RecCount;
end;
dsInsert:
OldRecCount := -1; { TQuery don't change RecordCount value after insert new record }
end;
Selected := FindNode(FDataLink.DataSet[FMasterField]);
end;
procedure TJvCustomDBTreeView.InternalDataScrolled;
begin
if not HandleAllocated or UpdateLocked then
Exit;
InDataScrolled := True;
try
DataScrolled;
finally
InDataScrolled := False;
end;
end;
procedure TJvCustomDBTreeView.DataScrolled;
begin
Selected := FindNode(FDataLink.DataSet[FMasterField]);
end;
procedure TJvCustomDBTreeView.Change(Node: TTreeNode);
var
OldState: TDataSetState;
begin
if ValidDataSet and Assigned(Node) and not InDataScrolled and
(FUpdateLock = 0) and
(FDataLink.DataSet.State in [dsBrowse, dsEdit, dsInsert]) then
begin
OldState := FDataLink.DataSet.State;
Inc(FUpdateLock);
try
Change2(Node);
finally
Dec(FUpdateLock);
end;
case OldState of
dsEdit:
FDataLink.DataSet.Edit;
dsInsert:
FDataLink.DataSet.Insert;
end;
end;
inherited Change(Node);
end;
procedure TJvCustomDBTreeView.Change2(Node: TTreeNode);
begin
FDataLink.DataSet.Locate(FMasterField, (Node as TJvDBTreeNode).FMasterValue, []);
if (Node as TJvDBTreeNode).FMasterValue = Null then
(Node as TJvDBTreeNode).SetMasterValue(FDataLink.DataSet.FieldByName(MasterField).AsVariant);
end;
procedure TJvCustomDBTreeView.InternalRecordChanged(Field: TField);
begin
if not (HandleAllocated and ValidDataSet) then
Exit;
if (Selected <> nil) and (FUpdateLock = 0) and
(FDataLink.DataSet.State = dsEdit) then
begin
Inc(FUpdateLock);
try
RecordChanged(Field);
finally
Dec(FUpdateLock);
end;
end;
end;
procedure TJvCustomDBTreeView.RecordChanged(Field: TField);
var
Node: TJvDBTreeNode;
begin
Selected.Text := FDataLink.DataSet.FieldByName(FItemField).Text;
with Selected as TJvDBTreeNode do
if FIconField <> '' then
begin
ImageIndex := Var2Type(FDataLink.DataSet[FIconField], varInteger);
SelectedIndex := ImageIndex + FSelectedIndex;
end;
{*** ParentNode changed ?}
if ((Selected.Parent <> nil) and
(FDataLink.DataSet[FDetailField] <> (Selected.Parent as TJvDBTreeNode).FMasterValue)) or
((Selected.Parent = nil) and
(FDataLink.DataSet[FDetailField] <> FStartMasterValue)) then
begin
Node := FindNode(FDataLink.DataSet[FDetailField]);
if (FDataLink.DataSet[FDetailField] = FStartMasterValue) or (Node <> nil) then
(Selected as TJvDBTreeNode).MoveTo(Node, naAddChild)
else
Selected.Free;
end;
{###}
{*** MasterValue changed ?}
if (FDataLink.DataSet[FMasterField] <> (Selected as TJvDBTreeNode).FMasterValue) then
begin
with (Selected as TJvDBTreeNode) do
begin
FMasterValue := FDataLink.DataSet[FMasterField];
if FIconField <> '' then
begin
ImageIndex := Var2Type(FDataLink.DataSet[FIconField], varInteger);
SelectedIndex := ImageIndex + FSelectedIndex;
end;
end;
{what have I do with Children ?}
{if you know, place your code here...}
end;
{###}
end;
function TJvCustomDBTreeView.CanEdit(Node: TTreeNode): Boolean;
begin
Result := inherited CanEdit(Node);
if FDataLink.DataSet <> nil then
Result := Result and not FDataLink.ReadOnly;
end;
procedure TJvCustomDBTreeView.Edit(const Item: TTVItem);
begin
CheckDataSet;
inherited Edit(Item);
if Assigned(Selected) then
begin
Inc(FUpdateLock);
try
if Item.pszText <> nil then
begin
if FDataLink.Edit then
FDataLink.DataSet.FieldByName(FItemField).Text := Item.pszText;
try
FDataLink.DataSet.Post;
Change2(Self.Selected); {?}
except
on E: Exception do
begin
DataLink.DataSet.Cancel;
if InAddChild then
begin
Self.Selected.Free;
if Sel <> nil then
Selected := Sel;
end;
raise;
end;
end;
end
else
begin
FDataLink.DataSet.Cancel;
if InAddChild then
begin
Self.Selected.Free;
if Sel <> nil then
Selected := Sel;
end;
end;
finally
InAddChild := False;
Dec(FUpdateLock);
end;
end;
end;
function TJvCustomDBTreeView.AddChildNode(const Node: TTreeNode; const Select: Boolean): TJvDBTreeNode;
var
MV: Variant;
M: string;
begin
CheckDataSet;
if Assigned(Node) then
MV := (Node as TJvDBTreeNode).FMasterValue
else
MV := FStartMasterValue;
if Assigned(Node) and Node.HasChildren and (Node.Count = 0) then
RefreshChild(Node as TJvDBTreeNode);
Inc(FUpdateLock);
InAddChild := True;
try
OldRecCount := FDataLink.DataSet.RecordCount + 1;
FDataLink.DataSet.Append;
FDataLink.DataSet[FDetailField] := MV;
if FDataLink.DataSet.FieldValues[FItemField] = Null then
M := ''
else
M := FDataLink.DataSet.FieldByName(FItemField).Text;
Result := Items.AddChild(Node, M) as TJvDBTreeNode;
with Result do
begin
FMasterValue := FDataLink.DataSet.FieldValues[FMasterField];
if FIconField <> '' then
begin
ImageIndex := Var2Type(FDataLink.DataSet[FIconField], varInteger);
SelectedIndex := ImageIndex + FSelectedIndex;
end;
end;
Result.Selected := Select;
{ This line is very necessary, well it(he) does not understand from the first [translated]}
Result.Selected := Select;
finally
Dec(FUpdateLock);
end;
end;
procedure TJvCustomDBTreeView.DeleteNode(Node: TTreeNode);
var
NewSel: TTreeNode;
begin
CheckDataSet;
Inc(FUpdateLock);
InDelete := True;
try
NewSel := FindNextNode(Selected);
FDataLink.DataSet.Delete;
Selected.Free;
if NewSel <> nil then
NewSel.Selected := True;
finally
InDelete := False;
Dec(FUpdateLock);
end;
end;
function TJvCustomDBTreeView.FindNextNode(const Node: TTreeNode): TTreeNode;
begin
if (Node <> nil) and (Node.Parent <> nil) then
if Node.Parent.Count > 1 then
if Node.Index = Node.Parent.Count - 1 then
Result := Node.Parent[Node.Index - 1]
else
Result := Node.Parent[Node.Index + 1]
else
Result := Node.Parent
else
{ if Items.Count > 1 then
if Node.Index = Items.Count-1 then
Result := Items[Node.Index-1] else
Result := Items[Node.Index+1]
else}
Result := nil;
end;
procedure TJvCustomDBTreeView.MoveTo(Source, Destination: TJvDBTreeNode; Mode: TNodeAttachMode);
var
MV, V: Variant;
begin
CheckDataSet;
if FUpdateLock = 0 then
begin
Inc(FUpdateLock);
try
MV := Source.FMasterValue;
if FDataLink.DataSet.Locate(FMasterField, MV, []) and FDataLink.Edit then
begin
case Mode of
naAdd:
if Destination.Parent <> nil then
V := (Destination.Parent as TJvDBTreeNode).FMasterValue
else
V := FStartMasterValue;
naAddChild:
V := Destination.FMasterValue;
else
raise EJvDBTreeViewError.CreateRes(@RsEMoveToModeError);
end;
FDataLink.DataSet[FDetailField] := V;
end;
finally
Dec(FUpdateLock);
end;
end;
end;
{******************* Drag'n'Drop ********************}
procedure TJvCustomDBTreeView.TimerDnDTimer(Sender: TObject);
begin
if YDragPos < DnDScrollArea then
Perform(WM_VSCROLL, SB_LINEUP, 0)
else
if YDragPos > ClientHeight - DnDScrollArea then
Perform(WM_VSCROLL, SB_LINEDOWN, 0);
end;
procedure TJvCustomDBTreeView.DragOver(Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
var
Node: TTreeNode;
HT: THitTests;
begin
inherited DragOver(Source, X, Y, State, Accept);
if ValidDataSet and (DragMode = dmAutomatic) and
not FDataLink.ReadOnly and not Accept then
begin
HT := GetHitTestInfoAt(X, Y);
Node := GetNodeAt(X, Y);
Accept := (Source = Self) and Assigned(Selected) and
(Node <> Selected) and Assigned(Node) and
not Node.HasAsParent(Selected) and
(HT - [htOnLabel, htOnItem, htOnIcon, htNowhere, htOnIndent, htOnButton] <> HT);
YDragPos := Y;
TimerDnD.Enabled := ((Y < DnDScrollArea) or (Y > ClientHeight - DnDScrollArea));
end;
end;
procedure TJvCustomDBTreeView.DragDrop(Source: TObject; X, Y: Integer);
var
AnItem: TTreeNode;
AttachMode: TNodeAttachMode;
HT: THitTests;
begin
TimerDnD.Enabled := False;
inherited DragDrop(Source, X, Y);
AnItem := GetNodeAt(X, Y);
if ValidDataSet and (DragMode = dmAutomatic) and Assigned(Selected) and Assigned(AnItem) then
begin
HT := GetHitTestInfoAt(X, Y);
if (HT - [htOnItem, htOnLabel, htOnIcon, htNowhere, htOnIndent, htOnButton] <> HT) then
begin
if (HT - [htOnItem, htOnLabel, htOnIcon] <> HT) then
AttachMode := naAddChild
else
AttachMode := naAdd;
(Selected as TJvDBTreeNode).MoveTo(AnItem, AttachMode);
end;
end;
{
var
AnItem: TTreeNode;
AttachMode: TNodeAttachMode;
HT: THitTests;
begin
if TreeView1.Selected = nil then
Exit;
HT := TreeView1.GetHitTestInfoAt(X, Y);
AnItem := TreeView1.GetNodeAt(X, Y);
if (HT - [htOnItem, htOnIcon, htNowhere, htOnIndent] <> HT) then
begin
if (htOnItem in HT) or (htOnIcon in HT) then
AttachMode := naAddChild
else
if htNowhere in HT then
AttachMode := naAdd
else
if htOnIndent in HT then
AttachMode := naInsert;
TreeView1.Selected.MoveTo(AnItem, AttachMode);
end;
end;
}
end;
{################### Drag'n'Drop ####################}
procedure TJvCustomDBTreeView.KeyDown(var Key: Word; Shift: TShiftState);
procedure DeleteSelected;
var
M: string;
begin
if Selected.HasChildren then
M := RsDeleteNode2
else
M := RsDeleteNode;
if MessageDlg(Format(M, [Selected.Text]), mtConfirmation, [mbYes, mbNo], 0) = mrYes then
DeleteNode(Selected);
end;
begin
inherited KeyDown(Key, Shift);
if not ValidDataSet or (FDataLink.ReadOnly) or ReadOnly then
Exit;
case Key of
VK_DELETE:
if ([ssCtrl] = Shift) and Assigned(Selected) then
DeleteSelected;
VK_INSERT:
if not IsEditing then
begin
Sel := Selected;
if not Assigned(Selected) or ([ssAlt] = Shift) then
//AddChild
AddChildNode(Selected, True).EditText
else
//Add
AddChildNode(Selected.Parent, True).EditText;
end;
VK_F2:
if Selected <> nil then
Selected.EditText;
end;
end;
procedure TJvCustomDBTreeView.SetMirror(Value: Boolean);
begin
{$IFDEF VCL}
if Value and SysLocale.MiddleEast and not (csDesigning in ComponentState) then
MirrorControl(Self, Value);
{$ENDIF VCL}
FMirror := Value;
end;
{$IFDEF UNITVERSIONING}
initialization
RegisterUnitVersion(HInstance, UnitVersioning);
finalization
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -