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

📄 systemcontrolpack.pas

📁 动态提示控件
💻 PAS
📖 第 1 页 / 共 3 页
字号:
    {$IFDEF DFS_SCP_SYSTREEVIEW}
    property TreeView: TdfsCustomSystemTreeView
       read FTreeView write SetTreeView;
    {$ENDIF}
    {$IFDEF DFS_SCP_SYSLISTVIEW}
    property ListView: TdfsCustomSystemListView
       read FListView write SetListView;
    {$ENDIF}

  public
    { Overriden Methods }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    { New Public Methods }
    // Descendant implementation notes:  resets the control entirely.  This
    // implementatino does nothing but notify linked controls of the change.
    procedure Reset; dynamic;
    // Usage note:  GetSelectionPIDL and GetSelectionParentFolder must be able to
    // return the new value before this method is called.
    procedure NotifyLinkedControls(ForceUpdate: boolean); dynamic;
    procedure LinkedControlChanged(Sender: TObject; ForceUpdate: boolean); dynamic;

    { New Properties }
    property SelectionPIDL: PItemIDList
       read GetSelectionPIDL;
    property SelectionParentFolder: IShellFolder
       read GetSelectionParentFolder;

    { Modified Existing Properties }
    // Leave Items public because you can't change at design-time.  Also, don't
    // store the stuff in it, it's system dependent and must be built when run.
    property Items stored FALSE;
  end;
{$ENDIF} // DFS_SCP_SYSCOMBOBOX

implementation

uses
  Graphics, Forms, dialogs,
  {$IFDEF DFS_DEBUG} EJHkEng, {$ENDIF}
  {$IFDEF DFS_COMPILER_4_UP} ImgList, {$ENDIF}
  ShellAPI, PidlHelp;


{$IFDEF DFS_SCP_SYSTREEVIEW}
var
  FTimerTrees: TList;
  FMainWinHookSet: boolean;
  FMyComputerID: PItemIDList;

procedure TimerCallback(Wnd: HWND; Msg, TimerID: UINT; CurTime: DWORD); stdcall;
var
  x: integer;
begin
  for x := 0 to FTimerTrees.Count - 1 do
    if TdfsCustomSystemTreeView(FTimerTrees[x]).FReadDelayTimer = TimerID then
    begin
      TdfsCustomSystemTreeView(FTimerTrees[x]).TimerEvent;
      break;
    end;
end;

{ TdfsCustomSystemTreeView }

function TdfsCustomSystemTreeView.AppWinHook(var Message: TMessage): boolean;
begin
  if (Message.Msg = WM_DEVICECHANGE) and ((Message.WParam = $8000) or
    (Message.WParam = $8004)) then
    DeviceChanged;
  Result := FALSE;
end;

procedure TdfsCustomSystemTreeView.Change(Node: TTreeNode);
begin
  inherited Change(Node);

  if (FReadDelay > 0) and (not FInhibitReadDelay) then
  begin
    // Delay refreshing linked.  Do it when the timer fires.
    if FReadDelayTimer <> 0 then
      KillTimer(0, FReadDelayTimer);
    FReadDelayTimer := SetTimer(0, STV_READ_DELAY_TIMER, FReadDelay, @TimerCallback);
  end else begin
    // No read delay, just tell them to refresh now.
    if ([csLoading] * ComponentState) = [] then
      FInhibitReadDelay := FALSE;
    NotifyLinkedControls(FALSE);
  end;
end;

procedure TdfsCustomSystemTreeView.CMSysColorChange(var Message: TWMSysColorChange);
var
  RealColor: TColor;
begin
  SetupImageList;

  inherited;

  // There is apparently a bug in the VCl that doesn't correctly reset the
  // tree/list color on a system color change.  The window background color gets
  // changed correctly, but the text background color doesn't.  This may be
  // specific to D4, I'm not certain.
  RealColor := Color;
  // Change the color to something else, doesn't matter what so long as it's
  // different.
  if Color = clBlack then
    Color := clWhite
  else
    Color := clBlack;
  // Put back the real color
  Color := RealColor;
end;

constructor TdfsCustomSystemTreeView.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  FTimerTrees.Add(Self);
  FReadDelay := 500;
  FReadDelayTimer := 0;
  FInhibitReadDelay := TRUE;

  HookMainWin;

  // Initialize the image list to the system's image list
  SetupImageList;
end;

{$IFDEF DFS_SCP_BROKEN_COLOR}
procedure TdfsCustomSystemTreeView.CreateWnd;
begin
  inherited;
  Perform(TVM_SETBKCOLOR, 0, LPARAM(ColorToRGB(Color)));
  Perform(TVM_SETTEXTCOLOR, 0, LPARAM(ColorToRGB(Font.Color)));
end;
{$ENDIF}

destructor TdfsCustomSystemTreeView.Destroy;
begin
  if FMainWinHookSet then
  begin
    Application.UnHookMainWindow(AppWinHook);
    FMainWinHookSet := FALSE;
  end;

  if FReadDelayTimer <> 0 then
    KillTimer(0, FReadDelayTimer);
  FTimerTrees.Remove(Self);

  inherited Destroy;
end;

procedure TdfsCustomSystemTreeView.DeviceChanged;
begin
  // One of the drives changed.
  Reset;
end;

function TdfsCustomSystemTreeView.GetValidHandle: HWND;
begin
  if HandleAllocated then
    Result := Handle
  else if assigned(Parent) and Parent.HandleAllocated then
    Result := Parent.Handle
  else if (GetParentForm(Self) <> NIL) and
     (GetParentForm(Self).HandleAllocated) then
    Result := GetParentForm(Self).Handle
  else if assigned(Application.MainForm) and
     Application.MainForm.HandleAllocated then
    Result := Application.MainForm.Handle
  else
    Result := 0;
end;

procedure TdfsCustomSystemTreeView.HookMainWin;
begin
  if not FMainWinHookSet then
  begin
    Application.HookMainWindow(AppWinHook);
    FMainWinHookSet := TRUE;
  end;
end;

procedure TdfsCustomSystemTreeView.LinkedControlChanged(Sender: TObject;
   ForceUpdate: boolean);
begin
  if csDesigning in ComponentState then
    exit;

  // Have to get linked's new pidl and refresh using it
  {$IFDEF DFS_SCP_SYSLISTVIEW}
  if (Sender = ListView) then
    LinkedReset(ListView.SelectionParentFolder, ListView.SelectionPIDL,
       ForceUpdate);
  {$ENDIF}

  {$IFDEF DFS_SCP_SYSCOMBOBOX}
  if (Sender = ComboBox) then
    LinkedReset(ComboBox.SelectionParentFolder, ComboBox.SelectionPIDL,
       ForceUpdate);
  {$ENDIF}
end;

procedure TdfsCustomSystemTreeView.Notification(AComponent: TComponent;
  AOperation: TOperation);
begin
  inherited Notification(AComponent, AOperation);

  case AOperation of
    opInsert:
      begin
        {$IFDEF DFS_SCP_SYSLISTVIEW}
        if (AComponent is TdfsCustomSystemListView) and (FListView = NIL) then
        begin
          ListView := TdfsCustomSystemListView(AComponent);
          ListView.TreeView := Self;
        end;
        {$ENDIF}

        {$IFDEF DFS_SCP_SYSCOMBOBOX}
        if (AComponent is TdfsCustomSystemComboBox) and (FComboBox = NIL) then
        begin
          ComboBox := TdfsCustomSystemComboBox(AComponent);
          ComboBox.TreeView := Self;
        end;
        {$ENDIF}
      end;

    opRemove:
      begin
        {$IFDEF DFS_SCP_SYSLISTVIEW}
        if AComponent = FListView then
          ListView := NIL;
        {$ENDIF}

        {$IFDEF DFS_SCP_SYSCOMBOBOX}
        if AComponent = FComboBox then
          ComboBox := NIL;
        {$ENDIF}
      end;
  end;
end;

procedure TdfsCustomSystemTreeView.NotifyLinkedControls(ForceUpdate: boolean);
begin
  {$IFDEF DFS_SCP_SYSLISTVIEW}
  if FListView <> NIL then
    ListView.LinkedControlChanged(Self, ForceUpdate);
  {$ENDIF}

  {$IFDEF DFS_SCP_SYSCOMBOBOX}
  if FComboBox <> NIL then
    ComboBox.LinkedControlChanged(Self, ForceUpdate);
  {$ENDIF}
end;

procedure TdfsCustomSystemTreeView.Reset;
begin
  NotifyLinkedControls(FALSE);
end;

{$IFDEF DFS_SCP_SYSCOMBOBOX}
procedure TdfsCustomSystemTreeView.SetComboBox(Val: TdfsCustomSystemComboBox);
begin
  if FComboBox <> Val then
  begin
    FComboBox := Val;
  end;
end;
{$ENDIF}

{$IFDEF DFS_SCP_SYSLISTVIEW}
procedure TdfsCustomSystemTreeView.SetListView(Val: TdfsCustomSystemListView);
begin
  if FListView <> Val then
  begin
    FListView := Val;
  end;
end;
{$ENDIF}

procedure TdfsCustomSystemTreeView.SetupImageList;
var
  SysIL: HImageList;
  SFI: TSHFileInfo;
begin
  if Images <> NIL then
    Images.Free;
  // Because we are the owner, it'll get freed automatically when we do.
  Images := TImageList.Create(Self);
  SysIL := SHGetFileInfo('', 0, SFI, SizeOf(SFI), SHGFI_SYSICONINDEX or
     SHGFI_SMALLICON);
  if SysIL <> 0 then
  begin
    if Images.HandleAllocated then
      Images.Handle := 0;
    Images.Masked := TRUE;
//    Images.BkColor := ImageList_GetBkColor(SysIL);
    Images.BkColor := clNone;
    Images.DrawingStyle := dsTransparent;
    Images.Handle := SysIL;
    Images.ShareImages := TRUE;  // DON'T FREE THE SYSTEM IMAGE LIST!!!!!
                                 // BAD IDEA (tm)!
  end;
end;

procedure TdfsCustomSystemTreeView.TimerEvent;
begin
  KillTimer(0, FReadDelayTimer);
  FReadDelayTimer := 0;
  // Delay timer fired, notify linked controls
  NotifyLinkedControls(FALSE);
end;

{$ENDIF}




{$IFDEF DFS_SCP_SYSLISTVIEW}

{ TdfsCustomSystemListView }

function TdfsCustomSystemListView.AppWinHook(var Message: TMessage): boolean;
begin
  if (Message.Msg = WM_DEVICECHANGE) and ((Message.WParam = $8000) or
    (Message.WParam = $8004)) then
    DeviceChanged;
  Result := FALSE;
end;

procedure TdfsCustomSystemListView.CMSysColorChange(var Message: TWMSysColorChange);
var
  RealColor: TColor;
begin
  SetupImageList;
  inherited;

  // There is apparently a bug in the VCl that doesn't correctly reset the
  // tree/list color on a system color change.  The window background color gets
  // changed correctly, but the text background color doesn't.  This may be
  // specific to D4, I'm not certain.
  RealColor := Color;
  // Change the color to something else, doesn't matter what so long as it's
  // different.
  if Color = clBlack then
    Color := clWhite
  else
    Color := clBlack;
  // Put back the real color
  Color := RealColor;
end;


constructor TdfsCustomSystemListView.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  HookMainWin;
  // Initialize the image list to the system's image list
  SetupImageList;
end;

{$IFDEF DFS_SCP_BROKEN_COLOR}
procedure TdfsCustomSystemListView.CreateWnd;
begin
  inherited;
  Perform(LVM_SETBKCOLOR, 0, LPARAM(ColorToRGB(Color)));
end;
{$ENDIF}

destructor TdfsCustomSystemListView.Destroy;
begin
  if FMainWinHookSet then
  begin
    Application.UnHookMainWindow(AppWinHook);
    FMainWinHookSet := FALSE;
  end;

  inherited;
end;

procedure TdfsCustomSystemListView.DeviceChanged;
begin
  // One of the drives changed.
  {$IFDEF DFS_SCP_SYSTREEVIEW}
  if TreeView <> NIL then
    TreeView.Reset
  else
  {$ENDIF}
    Reset;
end;

function TdfsCustomSystemListView.GetValidHandle: HWND;
begin
  if HandleAllocated then
    Result := Handle
  else if assigned(Parent) and Parent.HandleAllocated then
    Result := Parent.Handle
  else if (GetParentForm(Self) <> NIL) and
     (GetParentForm(Self).HandleAllocated) then
    Result := GetParentForm(Self).Handle
  else if assigned(Application.MainForm) and
     Application.MainForm.HandleAllocated then
    Result := Application.MainForm.Handle
  else
    Result := 0;
end;

procedure TdfsCustomSystemListView.HookMainWin;
begin
  if not FMainWinHookSet then
  begin
    Application.HookMainWindow(AppWinHook);
    FMainWinHookSet := TRUE;
  end;
end;

procedure TdfsCustomSystemListView.LinkedControlChanged(Sender: TObject;
   ForceUpdate: boolean);
begin
  if csDesigning in ComponentState then
    exit;

⌨️ 快捷键说明

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