zoukankan      html  css  js  c++  java
  • 一个能接受外部拖拽的控件(文字或文件)

    恩....也是这2天写的一个小东西的需求, 可以拖拽外部文本文件, 或者选择的一段文本到Memo里显示

    查了一下资料, 主要从2个方面实现:

      1.拖拽文件实现WM_DROPFILES就可以了

      2.拖拽文本需要实现IDropTarget接口

    针对这个功能, 重新封装了一个Memo出来:

      TDropMemo = class(TMemo, IUnknown, IDropTarget)
      private
        FDropAccept: Boolean;
        FDTDropAccept: HResult;
        FFE: TFormatEtc;
        FRefCount: Integer;
      protected
        procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES;
        procedure SetDropAccept(const Value: Boolean);
        {IUnknown}
        function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
        function _AddRef: Integer; stdcall;
        function _Release: Integer; stdcall;
        {IDropTarget}
        function DragEnter(const dataObj: IDataObject; grfKeyState: Longint;
          pt: TPoint; var dwEffect: Longint): HResult; stdcall;
        function DragOver(grfKeyState: Longint; pt: TPoint;
          var dwEffect: Longint): HResult; stdcall;
        function DragLeave: HResult; stdcall;
        function Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint;
          var dwEffect: Longint): HResult; stdcall;
      public
        property DropAccept: Boolean read FDropAccept write SetDropAccept;
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
      end;
    
    //--------------------------------------------------
    
    { TDragMemo }
    
    constructor TDropMemo.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      FRefCount := 0;
    end;
    
    destructor TDropMemo.Destroy;
    begin
      inherited;
    end;
    
    function TDropMemo.DragEnter(const dataObj: IDataObject; grfKeyState: Integer; pt: TPoint;
      var dwEffect: Integer): HResult;
    begin
      Result := E_FAIL;
      FDTDropAccept := E_FAIL;
    
      if not FDropAccept then
        Exit;
    
      if not Assigned(dataObj) then
        Exit;
    
      with FFE do
      begin
    {$IFDEF UNICODE}
        cfFormat := CF_UNICODETEXT;
    {$ELSE}
        cfFormat := CF_TEXT;
    {$ENDIF}
        ptd := nil;
        dwAspect := DVASPECT_CONTENT;
        lindex := -1;
        tymed := TYMED_HGLOBAL;
      end;
      FDTDropAccept := dataObj.QueryGetData(FFE);
      Result := FDTDropAccept;
      if not FAILED(Result) then
        dwEffect := DROPEFFECT_COPY
      else
        dwEffect := DROPEFFECT_NONE;
    end;
    
    function TDropMemo.DragLeave: HResult;
    begin
      Result := S_OK;
    end;
    
    function TDropMemo.DragOver(grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult;
    begin
      Result := S_OK;
    end;
    
    function TDropMemo.Drop(const dataObj: IDataObject; grfKeyState: Integer; pt: TPoint;
      var dwEffect: Integer): HResult;
    var
      nMedium: stgMedium;
      nHData: HGLOBAL;
    begin
      Result := E_FAIL;
    
      if FAILED(FDTDropAccept) then
        Exit;
    
      Result := dataObj.GetData(FFE, nMedium);
      nHData := HGLOBAL(GlobalLock(nMedium.hGlobal));
      try
        SendMessage(Handle, WM_SETTEXT, 0, nHData);
      finally
        GlobalUnlock(nHData);
        GlobalFree(nHData);
      end;
    end;
    
    function TDropMemo.QueryInterface(const IID: TGUID; out Obj): HResult;
    begin
      if GetInterface(IID, Obj) then
        Result := S_OK
      else
        Result := E_NOINTERFACE;
    end;
    
    procedure TDropMemo.SetDropAccept(const Value: Boolean);
    begin
      FDropAccept := Value;
      DragAcceptFiles(Handle, FDropAccept);
      if FDropAccept then
        RegisterDragDrop(Handle, Self)
      else
        RevokeDragDrop(Handle);
    end;
    
    procedure TDropMemo.WMDropFiles(var Msg: TWMDropFiles);
    var
      nBuffer: array[0..255] of Char;
      nCount: Integer;
      nFile: string;
    begin
      with Msg do
      begin
        nCount := DragQueryFile(Drop, $FFFFFFFF, nBuffer, 1);
        if nCount = 0 then
          Exit;
        DragQueryFile(Drop, 0, nBuffer, SizeOf(nBuffer));
        nFile := nBuffer;
        DragFinish(Drop);
      end;
      Lines.LoadFromFile(nFile);
    end;
    
    function TDropMemo._AddRef: Integer;
    begin
      Result := InterLockedDecrement(FRefCount);
      if Result = 0 then
        Destroy;
    end;
    
    function TDropMemo._Release: Integer;
    begin
      Result := InterLockedIncrement(FRefCount);
    end;

    使用的时候, 通过DropAccept属性控制是否开启过拽支持

    这个只是支持拖拽到Memo内, 如果想实现拖拽Memo内容到外部, 还需要再实现IDropSource接口, 因为没需求就懒得做了, 哪位有空闲可以一起实现了

    另外, 从网上找了一个别人封装的拖拽控件, 基本可以支持所有文本编辑控件:

      TDropText = class(TObject, IUnknown, IDropTarget)
      private
        FHandle: THandle;
        FCanDrop: HResult;
        FFE: TFormatEtc;
        FRefCount: Integer;
      protected
        {IUnknown}
        function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
        function _AddRef: Integer; stdcall;
        function _Release: Integer; stdcall;
        {IDropTarget}
        function DragEnter(const dataObj: IDataObject; grfKeyState: Longint;
          pt: TPoint; var dwEffect: Longint): HResult; stdcall;
        function DragOver(grfKeyState: Longint; pt: TPoint;
          var dwEffect: Longint): HResult; stdcall;
        function DragLeave: HResult; stdcall;
        function Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint;
          var dwEffect: Longint): HResult; stdcall;
      public
        constructor Create(AHandle: THandle);
        destructor Destroy; override;
      end;
    
    //----------------------------------------
    
    function TDropText._AddRef: Integer;
    begin
      Result := InterLockedDecrement(FRefCount);
      if Result = 0 then
        Destroy;
    end;
    
    function TDropText._Release: Integer;
    begin
      Result := InterLockedIncrement(FRefCount);
    end;
    
    constructor TDropText.Create(AHandle: THandle);
    begin
      FRefCount := 0;
      FHandle := AHandle;
      RegisterDragDrop(FHandle, Self);
    end;
    
    destructor TDropText.Destroy;
    begin
      RevokeDragDrop(FHandle);
      inherited;
    end;
    
    function TDropText.DragEnter(const dataObj: IDataObject;
      grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult;
    begin
      Result := E_FAIL;
      FCanDrop := E_FAIL;
    
      if not Assigned(dataObj) then
        Exit;
    
      with FFE do
      begin
    {$IFDEF UNICODE}
        cfFormat := CF_UNICODETEXT;
    {$ELSE}
        cfFormat := CF_TEXT;
    {$ENDIF}
        ptd := nil;
        dwAspect := DVASPECT_CONTENT;
        lindex := -1;
        tymed := TYMED_HGLOBAL;
      end;
      FCanDrop := dataObj.QueryGetData(FFE);
      Result := FCanDrop;
      if not FAILED(Result) then
        dwEffect := DROPEFFECT_COPY
      else
        dwEffect := DROPEFFECT_NONE;
    end;
    
    function TDropText.DragLeave: HResult;
    begin
      Result := S_OK;
    end;
    
    function TDropText.DragOver(grfKeyState: Integer; pt: TPoint;
      var dwEffect: Integer): HResult;
    begin
      Result := S_OK;
    end;
    
    function TDropText.Drop(const dataObj: IDataObject; grfKeyState: Integer;
      pt: TPoint; var dwEffect: Integer): HResult;
    var
      nMedium: stgMedium;
      nHData: HGLOBAL;
    begin
      Result := E_FAIL;
    
      if FAILED(FCanDrop) then
        Exit;
    
      Result := dataObj.GetData(FFE, nMedium);
      nHData := HGLOBAL(GlobalLock(nMedium.hGlobal));
      try
        SendMessage(FHandle, WM_SETTEXT, 0, nHData);
      finally
        GlobalUnlock(nHData);
        GlobalFree(nHData);
      end;
    end;
    
    function TDropText.QueryInterface(const IID: TGUID; out Obj): HResult;
    begin
      if GetInterface(IID, Obj) then
        Result := S_OK
      else
        Result := E_NOINTERFACE;
    end;

    调用方式:

       FDragText:= TDropText.Create(Memo1.Handle);

    这样就可以让任何拥有文字编辑功能的控件支持文字拖拽的效果了

  • 相关阅读:
    JVM运行时数据区及对象在内存中初始化的过程
    一文搞懂List 、List<Object>、List<?>的区别以及<? extends T>与<? super T>的区别
    Java中创建泛型数组
    JavaBean详解
    Java常用命令及参数
    一文彻底搞懂Java中的环境变量
    类型信息
    java中的数组
    URL与URI的区别
    上行速率和下行速率
  • 原文地址:https://www.cnblogs.com/lzl_17948876/p/3926709.html
Copyright © 2011-2022 走看看