一个能接受外部拖拽的控件(文字或文件)

恩....也是这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);

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

一个能接受外部拖拽的控件(文字或文件)

时间: 2024-10-07 09:10:26

一个能接受外部拖拽的控件(文字或文件)的相关文章

ios 为什么拖拽的控件为weak 手写的strong

ib拖拽的控件自动声明为weak  而平时自己手写的为strong 在ios中,对象默认都是强引用,不是强引用赋值后会立即释放 ib声明weak 不立即被释放 简单说就是 1.声明的弱引用指向强引用 2.加到了view中 @property (nonatomic, weak) UILabel * lab; ..... -(void)viewDidLoad { UILabel * label = [ UILabel alloc] init.... _lab = label; [self.view

独家原创,拖拽任意控件移动任意目标,拖拽控件移动整个窗体

独家原创,拖拽任意控件移动任意目标,拖拽控件移动整个窗体,在无边框窗体及其友好的实现拖拽移动窗体 http://www.cnblogs.com/vonly/ only原创首发,vonly.net 1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Configuration; 5 using System.Diagnostics; 6 using Sys

ImageView图片拖拽缩放控件

1.在父控件为Viewpager的背景实现,所以会处理图片左右滑动和Viewpager滑动 的冲突 package com.example.widget; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.PointF; import androi

VS2010 VS2012拖拽NumericUpDown控件直接卡死的解决办法

昨天晚上画界面过程中碰到这个问题,本以为是VS的bug,并没在意gg了一个2010的Sp1补丁,之后进入官方下载器,50mb/s的网,大概更新了3-4个小时.今天晚上到了画界面的时间准备开始就又碰到了这个问题,我就立刻的换了2012尝试,同样的结果,索性在群里问了问没人搭理我,故不断的google,终于找到一个说是是是是有道字典和vs冲突,关掉了有道,问题解决啦!解决方案就是关掉关关关关关关有道,如果你也碰到这个问题,希望对您有帮助吧

每天一个JavaScript实例-html5拖拽

<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>每天一个JavaScript实例-html5拖拽</title> <style> #drop{ width:300px; height:200px; background-

.NET成人礼 | 还记得20年前一起拖过的控件吗?

本文是MVP Ediwang写的回忆一个80后的拖控件的感悟,与君共勉: 每一代人都有记忆里的味道.煤球炉.黑白电视机是属于父母的记忆.而“拖控件”式编程,启蒙了无数像我这样的80后(嗯,89也算80后). 经典旧世 2000 年那个时候,上海这样的城市里也不是每家每户都有电脑,我家也没有电脑.我在学校经常听几位家里条件不错的同学说他们玩电脑的事情.CIH.千年虫等名词让我对电脑有着非常强烈的好奇心.而我第一次体验到计算机,是在我母亲单位的机房里.它是一台卧式机箱.15寸 CRT 凸面屏显示器的

如果写一个android桌面滑动切换屏幕的控件(二)

在viewgroup执行: public void snapToScreen(int whichScreen) { whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); boolean changingScreens = whichScreen != mCurrentScreen; mNextScreen = whichScreen; int mScrollX = this.getScrollX(); fin

如果写一个android桌面滑动切换屏幕的控件(三)

下面我们把这个控件内嵌到Layout中做一些动画和展示,效果图: 这个子控件可以上下移动,可以左右滑动,如果上下滑动距离大于左右滑动距离,则必须上下滑动 这样来写onTouch事件: @Override public boolean onTouchEvent(MotionEvent ev) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMov

如果写一个android桌面滑动切换屏幕的控件(一)

首先这个控件应该是继承ViewGroup: 初始化: public class MyGroup extends ViewGroup{ private Scroller mScroller; private float mOriMotionX; private float mLastMotionX; private VelocityTracker mVelocityTracker; private int mTouchState = TOUCH_STATE_REST; private static