📄 shellctrls.pas
字号:
begin
Data := TShellFolder.Create(nil, FRootFolder.AbsoluteID, FRootFolder.ShellFolder);
Text := GetDisplayName(DesktopShellFolder,
TShellFolder(Data).AbsoluteID,
SHGDN_NORMAL);
if FUseShellImages and not Assigned(Images) then
begin
RootNode.ImageIndex := GetShellImage(TShellFolder(RootNode.Data).AbsoluteID, False, False);
RootNode.SelectedIndex := GetShellImage(TShellFolder(RootNode.Data).AbsoluteID, False, True);
end;
RootNode.HasChildren := TShellFolder(RootNode.Data).SubFolders;
end;
RootNode.Expand(False);
Selected := RootNode;
finally
FLoadingRoot := False;
end;
end;
if ErrorMsg <> '' then
Raise Exception.Create( ErrorMsg );
end;
function TCustomShellTreeView.CanExpand(Node: TTreeNode): Boolean;
var
Fldr: TShellFolder;
begin
Result := True;
Fldr := TShellFolder(Node.Data);
if (csDesigning in ComponentState) and (Node.Level > 0) then Exit;
if Assigned(OnExpanding) then OnExpanding(Self, Node, Result);
if Result then
if Fldr.IsFolder and (Node.HasChildren) and (Node.Count = 0) then
PopulateNode(Node)
else if not Fldr.IsFolder then
begin
ShellExecute(Handle, nil, PChar(Fldr.PathName), nil,
PChar(ExtractFilePath(Fldr.PathName)), 0);
end;
Node.HasChildren := Node.Count > 0;
end;
procedure TCustomShellTreeView.Edit(const Item: TTVItem);
var
S: string;
Node: TTreeNode;
begin
with Item do
if pszText <> nil then
begin
S := pszText;
Node := Items.GetNode(Item.hItem);
if Assigned(OnEdited) then OnEdited(Self, Node, S);
if ( Node <> nil ) and TShellFolder(Node.Data).Rename(S) then
Node.Text := S;
end;
end;
procedure TCustomShellTreeView.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
//! Commenting this out fixes #107480, #109250
(*
if (Button = mbRight) and FAutoContext and (Selected <> nil) and (Selected.Data <> nil) then
InvokeContextMenu(Self, SelectedFolder, X, Y)
else
(**)
inherited MouseUp(Button, Shift, X, Y);
end;
function TCustomShellTreeView.NodeFromRelativeID(ParentNode: TTreeNode; ID: PItemIDList): TTreeNode;
var
HR: HResult;
begin
Result := ParentNode.GetFirstChild;
while (Result <> nil) do
begin
HR := TShellFolder(ParentNode.Data).ShellFolder.CompareIDs(0, ID, TShellFolder(Result.Data).RelativeID);
if HR = 0 then Exit;
Result := ParentNode.GetNextChild(Result);
end;
end;
function TCustomShellTreeView.NodeFromAbsoluteID(StartNode: TTreeNode; ID: PItemIDList): TTreeNode;
var
HR: HResult;
begin
Result := StartNode;
while Result <> nil do
begin
HR := DesktopShellFolder.CompareIDs(0, ID, TShellFolder(Result.Data).AbsoluteID);
if HR = 0 then Exit;
Result := Result.GetNext;
end;
end;
procedure TCustomShellTreeView.Delete(Node: TTreeNode);
begin
if Assigned(Node.Data) then
begin
TShellFolder(Node.Data).Free;
Node.Data := nil;
end;
inherited Delete(Node);
end;
(*
procedure TCustomShellTreeView.NodeDeleted(Sender: TObject; Node: TTreeNode);
begin
if Assigned(Node.Data) then
begin
TShellFolder(Node.Data).Free;
Node.Data := nil;
end;
end;
(**)
procedure TCustomShellTreeView.RootChanged;
begin
if FUpdating then Exit;
FUpdating := True;
try
CreateRoot;
if Assigned(FComboBox) then
FComboBox.SetRoot(FRoot);
if Assigned(FListView) then
FListView.SetRoot(FRoot);
finally
FUpdating := False;
end;
end;
function TCustomShellTreeView.FolderExists(FindID: PItemIDList; InNode: TTreeNode): TTreeNode;
var
ALevel: Integer;
begin
Result := nil;
ALevel := InNode.Level;
repeat
if DesktopShellFolder.CompareIDs(
0,
FindID,
TShellFolder(InNode.Data).AbsoluteID) = 0 then
begin
Result := InNode;
Exit;
end else
InNode := InNode.GetNext;
until (InNode = nil) or (InNode.Level <= ALevel);
end;
procedure TCustomShellTreeView.RefreshEvent;
begin
if Assigned(Selected) then
Refresh(Selected);
end;
procedure TCustomShellTreeView.Refresh(Node: TTreeNode);
var
NewNode, OldNode, Temp: TTreeNode;
OldFolder, NewFolder: TShellFolder;
ThisLevel: Integer;
SaveCursor: TCursor;
TopID, SelID: PItemIDList;
ParentFolder: TShellFolder;
begin
if TShellFolder(Node.Data).ShellFolder = nil then Exit;
SaveCursor := Screen.Cursor;
ParentFolder := nil;
//Need absolute PIDL to search for top item once tree is rebuilt.
TopID := CopyPIDL(TShellFolder(TopItem.Data).RelativeID);
if TShellFolder(TopItem.Data).Parent <> nil then
TopID := ConcatPIDLs(TShellFolder(TopItem.Data).Parent.AbsoluteID, TopID);
//Same thing for SelID
SelID := nil;
if (Selected <> nil) and (Selected.Data <> nil) then
begin
SelID := CopyPIDL(TShellFolder(Selected.Data).RelativeID);
if TShellFolder(Selected.Data).Parent <> nil then
SelID := ConcatPIDLs(TShellFolder(Selected.Data).Parent.AbsoluteID, SelID);
end;
Items.BeginUpdate;
try
Screen.Cursor := crHourglass;
OldFolder := Node.Data;
NewNode := Items.Insert(Node, '');
if Node.Parent <> nil then
ParentFolder := TShellFolder(Node.Parent.Data);
NewNode.Data := TShellFolder.Create(ParentFolder,
OldFolder.RelativeID,
OldFolder.ShellFolder);
PopulateNode(NewNode);
with NewNode do
begin
NewFolder := Data;
ImageIndex := GetShellImage(NewFolder.AbsoluteID, False, False);
SelectedIndex := GetShellImage(NewFolder.AbsoluteID, False, True);
HasChildren := NewFolder.SubFolders;
Text := NewFolder.DisplayName;
end;
ThisLevel := Node.Level;
OldNode := Node;
repeat
Temp := FolderExists(TShellFolder(OldNode.Data).AbsoluteID, NewNode);
if (Temp <> nil) and OldNode.Expanded then
Temp.Expand(False);
OldNode := OldNode.GetNext;
until (OldNode = nil) or (OldNode.Level = ThisLevel);
if Assigned(Node.Data) then
begin
TShellFolder(Node.Data).Free;
Node.Data := nil;
end;
Node.Delete;
if SelID <> nil then
begin
Temp := FolderExists(SelID, Items[0]);
Selected := Temp;
end;
Temp := FolderExists(TopID, Items[0]);
TopItem := Temp;
finally
Items.EndUpdate;
DisposePIDL(TopID);
if SelID <> nil then DisposePIDL(SelID);
Screen.Cursor := SaveCursor;
end;
end;
procedure TCustomShellTreeView.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) then
begin
if (AComponent = FComboBox) then
FComboBox := nil
else if (AComponent = FListView) then
FListView := nil;
end;
end;
function TCustomShellTreeView.CanChange(Node: TTreeNode): Boolean;
var
Fldr: TShellFolder;
StayFresh: boolean;
begin
Result := inherited CanChange(Node);
if Result and (not FUpdating) and Assigned(Node) then
begin
Fldr := TShellFolder(Node.Data);
StayFresh := FAutoRefresh;
AutoRefresh := False;
if not Fldr.IsFolder then
Fldr := Fldr.Parent;
FUpdating := True;
try
if Assigned(FComboBox) then
FComboBox.TreeUpdate(Fldr.AbsoluteID);
if Assigned(FListView) then
FListView.TreeUpdate(Fldr.AbsoluteID);
finally
FUpdating := False;
end;
FNodeToMonitor := Node;
try
AutoRefresh := StayFresh;
finally
FNodeToMonitor := nil;
end;
end;
end;
function TCustomShellTreeView.GetFolder(Index: Integer): TShellFolder;
begin
Result := TShellFolder(Items[Index].Data);
end;
function TCustomShellTreeView.SelectedFolder: TShellFolder;
begin
Result := nil;
if Selected <> nil then Result := TShellFolder(Selected.Data);
end;
function TCustomShellTreeView.GetPath: String;
begin
if SelectedFolder <> nil then
Result := SelectedFolder.PathName
else
Result := '';
end;
procedure TCustomShellTreeView.SetPath(const Value: string);
var
P: PWideChar;
NewPIDL: PItemIDList;
Flags,
NumChars: LongWord;
begin
NumChars := Length(Value);
Flags := 0;
P := StringToOleStr(Value);
try
OLECheck(DesktopShellFolder.ParseDisplayName(0, nil, P, NumChars,
NewPIDL, Flags));
SetPathFromID(NewPIDL);
except
on EOleSysError do
raise EInvalidPath.CreateFmt(SErrorSettingPath, [Value]);
end;
end;
procedure TCustomShellTreeView.SetPathFromID(ID: PItemIDList);
var
I: Integer;
Pidls: TList;
Temp, Node: TTreeNode;
begin
if FUpdating or (csLoading in ComponentState)
or ((SelectedFolder <> nil) and SamePIDL(SelectedFolder.AbsoluteID, ID)) then Exit;
FUpdating := True;
Items.BeginUpdate;
try
Pidls := CreatePIDLList(ID);
try
Node := Items[0];
for I := 0 to Pidls.Count-1 do
begin
Temp := FolderExists(Pidls[I], Node);
if Temp <> nil then
begin
Node := Temp;
Node.Expand(False);
end;
end;
Node := FolderExists(ID, Node);
Selected := Node;
if Assigned(Node) then
begin
if Assigned(FListView) then
FListView.TreeUpdate(TShellFolder(Node.Data).AbsoluteID);
if Assigned(FComboBox) then
FComboBox.TreeUpdate(TShellFolder(Node.Data).AbsoluteID);
end;
finally
DestroyPIDLList(Pidls);
end;
finally
Items.EndUpdate;
FUpdating := False;
end;
end;
procedure TCustomShellTreeView.SetRoot(const Value: TRoot);
begin
if not SameText(FRoot, Value) then
begin
FOldRoot := FRoot;
FRoot := Value;
RootChanged;
end;
end;
procedure TCustomShellTreeView.GetImageIndex(Node: TTreeNode);
begin
if Assigned(Images) then
inherited GetImageIndex(Node);
end;
procedure TCustomShellTreeView.GetSelectedIndex(Node: TTreeNode);
begin
if Assigned(Images) then
inherited GetSelectedIndex(Node);
end;
procedure TCustomShellTreeView.WndProc(var Message: TMessage);
var
ImageListHandle: THandle;
begin
case Message.Msg of
WM_INITMENUPOPUP,
WM_DRAWITEM,
WM_MENUCHAR,
WM_MEASUREITEM:
if Assigned(ICM2) then
begin
ICM2.HandleMenuMsg(Message.Msg, Message.wParam, Message.lParam);
Message.Result := 0;
end;
TVM_SETIMAGELIST:
if not FImageListChanging then
begin
FImageListChanging := True;
try
if not Assigned(Images) then
if FUseShellImages then
ImageListHandle := FImages
else
ImageListHandle := 0
else
ImageListHandle := Images.Handle;
SendMessage(Self.Handle, TVM_SETIMAGELIST, TVSIL_NORMAL, ImageListHandle);
//RootChanged;
finally
FImageListChanging := False;
end;
end
else inherited;
else
inherited WndProc(Message);
end;
end;
procedure TCustomShellTreeView.SetUseShellImages(const Value: Boolean);
var
ImageListHandle: THandle;
begin
FUseShellImages := Value;
if not Assigned(Images) then
if FUseShellImages then
ImageListHandle := FImages
else
ImageListHandle := 0
else
ImageListHandle := Images.Handle;
SendMessage(Handle, TVM_SETIMAGELIST, TVSIL_NORMAL, ImageListHandle);
end;
procedure TCustomShellTreeView.WMDestroy(var Message: TWMDestroy);
begin
ClearItems;
inherited;
end;
procedure TCustomShellTreeView.Loade
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -