窗体的控件可以随意拖放,而且所有容器支持控件拖放(前提),
现在我想通过SendMessage发送消息实现该控件的拖放,
请问如何实现?比如,窗体中的某个按钮(Button)在一个面板(Panel)上,
我现在知道该按钮(Button)的句柄,Panel的句柄可要可不要(我认为),
我想用SendMessage发送消息,使得按钮(Button)拖动到另一个面板(Panel)上,这个面板(Panel)的句柄也是可要可不要(我认为)。本人的想法是这样的:
1.先给按钮(Button)发送鼠标左键按下的消息 WM_LBUTTONDOWN
2.然后再发送鼠标移动的消息 WM_MOUSEMOVE 把鼠标移到另一个面板(Panel)上
3.最后再发送鼠标左键释放消息 WM_LBUTTONUP
问题是发送鼠标移动消息的时候,什么反应也没有,不知道 WM_MOUSEMOVE 这个消息是如何发送的,而且我查看过帮助,发送该消息时,可以再带个参数 MK_LBUTTON ,这样可以在移动的时候同时也按住鼠标左键,是这样吗?本人还想过另一种方法:
就是把按钮剪贴到剪贴板上,然后再从剪贴板复制到另一个面板上,这样会有什么问题吗?不过这样就需要知道目标面板(Panel)的句柄,而根据现有的条件,本人有可能无法获得目标Panel的句柄,因为是别人写的程序,里面的Panel很多,而且也没有相关的字符串标识(text,name或caption没有),但如果是鼠标拖动的话,可以找到位置(因为有相对位置)。还望各位高手指点一下如何实现,或者给点思路和意见,分不够可以再加!

解决方案 »

  1.   

    转篇贴子你参考一下//==============================================================================//任意摆布一个控件(拖动、放大、缩小)******************************************//==============================================================================procedure ManipulateControl(WinControl: TWinControl; Shift: TShiftState; X, Y, Precision: integer);//Precision:精度,该方法可以在onmousemove中调用var SC_MANIPULATE: Word;begin  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  //光标在控件的最左侧**********************************************************  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~       if (X<=Precision) and (Y>Precision) and (Y<WinControl.Height-Precision)  then begin         SC_MANIPULATE  := $F001;         WinControl.Cursor := crSizeWE;       end  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  //光标在控件的最右侧**********************************************************  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  else if (X>=WinControl.Width-Precision) and (Y>Precision) and (Y<WinControl.Height-Precision)  then begin         SC_MANIPULATE  := $F002;         WinControl.Cursor := crSizeWE;       end  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  //光标在控件的最上侧**********************************************************  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  else if (X>Precision) and (X<WinControl.Width-Precision) and (Y<=Precision)  then begin         SC_MANIPULATE  := $F003;         WinControl.Cursor := crSizeNS;       end  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  //光标在控件的左上角**********************************************************  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  else if (X<=Precision) and (Y<=Precision)  then begin         SC_MANIPULATE  := $F004;         WinControl.Cursor := crSizeNWSE;       end  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  //光标在控件的右上角**********************************************************  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  else if (X>=WinControl.Width-Precision) and (Y<=Precision)  then begin         SC_MANIPULATE  := $F005;         WinControl.Cursor := crSizeNESW ;       end  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  //光标在控件的最下侧**********************************************************  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  else if (X>Precision) and (X<WinControl.Width-Precision) and (Y>=WinControl.Height-Precision)  then begin         SC_MANIPULATE  := $F006;         WinControl.Cursor := crSizeNS;       end  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  //光标在控件的左下角**********************************************************  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  else if (X<=Precision) and (Y>=WinControl.Height-Precision)  then begin         SC_MANIPULATE  := $F007;         WinControl.Cursor := crSizeNESW;       end  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  //光标在控件的右下角**********************************************************  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  else if (X>=WinControl.Width-Precision) and (Y>=WinControl.Height-Precision)  then begin         SC_MANIPULATE  := $F008;         WinControl.Cursor := crSizeNWSE;       end  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  //光标在控件的客户区(移动整个控件)******************************************  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  else if (X>5) and (Y>5) and (X<WinControl.Width-5) and (Y<WinControl.Height-5)  then begin         SC_MANIPULATE  := $F009;         WinControl.Cursor := crSizeAll;       end  else begin         SC_MANIPULATE := $F000;         WinControl.Cursor := crDefault;       end;  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  if Shift=[ssLeft] then  begin    ReleaseCapture;    WinControl.Perform(WM_SYSCOMMAND, SC_MANIPULATE, 0);  end;  end;
    调用例子:
    procedure TForm_Main.Button1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);begin  Caption := IntToStr(X) + '/' + IntToStr(Y);  ManipulateControl((Sender as TWinControl), Shift, X, Y, 10);end;
      

  2.   

    给分吧。呵呵。
    ReleaseCapture是释放鼠标捕获,
    WinControl.Perform(WM_SYSCOMMAND, SC_MANIPULATE, 0);是向WinControl这个控件发消息.用SendMessage(WinControl.Handle, WM_SYSCOMMAND, SC_MANIPULATE, 0)也一样.
      

  3.   

    我想再说明一下:
    我要移动的控件不是自己程序的控件
    而是其他程序(别人写好的,而且开发语言是未知的)窗体里的控件
    我通过Windows API获得了该控件的句柄
    现在我想实现该控件的拖放
    拖放的过程及结果也是在其他程序的窗体里
    所以自己的程序的各种鼠标事件(MouseDown等等)应该是不适用的
    那样只能控制自己程序窗体的控件
    而不是其他程序窗体里的控件我不知道大家明白我的意思吗?
    我想通过自己的程序去控制别人的程序
    移动的控件在别人的程序里
    所以我认为只能通过发送消息来处理
    但我发送消息后并没有能实现
    鼠标左键按下和释放是可以的
    就是鼠标移动的时候没反应
    希望高手们帮我看看到底如何发送鼠标移动消息多谢楼上的兄弟,虽然你们结果不是我想要的
    这个问题现在是本人做的项目的一个难点
    希望更多的高手来帮忙解决这个问题
      

  4.   

    to XXSingle(三笑留情〓★▲◆) 
    本来客户提供的程序就是支持拖放的
    我的项目就是要做一个控制平台
    让用户可以在我的平台上控制客户自己的程序
    现在在拖放的实现上遇到了困难
    所以来求救了
    以前不是看到很多高手经常在这里活跃的吗
    现在怎么都不见了
    是放假了么
    高手们,帮帮忙啊,分不够再加
      

  5.   

    客户端提供的程序支持拖放
    也就是可以用鼠标拖放该程序的控件从一个位置到另一个位置
    就像我们打开文件夹一样
    里面的文件或文件夹都可以拖放
    不管实现原理如何
    只要我用鼠标点击拖放移动总是可以的吧
    既然可以
    那就应该可以通过发送消息去自动实现而不用手动去拖放
    目前我是发送WM_MOUSEMOVE消息时鼠标并没有移动
    这是什么原因?
      

  6.   

    能把你的那个客户程序发给我一份吗?我可以帮你试试
    我的mail是
    [email protected]
      

  7.   

    1。如果只是改变容器不一定要用脱放
    Option ExplicitPrivate Sub Command1_Click()
    Set Command3.Container = Picture1End SubPrivate Sub Command2_Click()
     Set Command3.Container = Frame1
    End Sub
      

  8.   

    to hkbarton(宁静至远)(西南交大) 
    感谢你的热情帮助
    不过客户程序是客户内部自己人开发的
    具有一定的保密性
    或者你自己写个小例子试试
    你可以写两个程序
    一个程序你可以设置窗体里的任意一个控件可以拖放(DragKind:=dkDock;DragMode:=Automatic)
    并在该窗体里放两个Panel,设置支持拖放(DokeSite:=True)
    不用添加什么代码,程序运行后,该控件可以通过鼠标在两个Panel里拖放
    然后你再写另一个程序,通过发送Windows消息去控制第一个程序里的控件
    让该控件也能在两个Panel里拖放
    我用SendMessage(句柄,WM_MOUSEMOVE, x,y);//其中x,y我不知道如何设置,查看相关资料,如果x设置为MK_LBUTTON时相当于移动鼠标的同时按下了鼠标左键,y是鼠标移动的位置,高16位是纵坐标,低16位是横坐标,你能帮我试试看,通过WM_MOUSEMOVE如何实现鼠标移动?发送消息时里面的参数是什么,写出一段通过消息能成功移动鼠标的代码就可以了。
    另外我还想问,如果用户需要移动的是文件夹里的文件或文件夹,不是通过复制粘贴,也是通过发送消息,让鼠标自动实现拖动文件或文件夹到新的位置,这样又该如何实现?因为文件夹的对象不像窗体对象一样可以获得句柄,或者还有什么新的方法吗?
    兄弟,拜托你了!
      

  9.   

    最简单的
    procedure TForm1.Button2MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    begin
      ReleaseCapture;
      Button2.Perform(WM_SYSCOMMAND,$f012,0);
    end;
      

  10.   

    你还可以判断时候通过了容器,如果时。就可以设置parent属性
      

  11.   

    to zsy_good(只要坚定不移的走下去,那一定会成功)
    不是这个意思
    不管怎样
    感谢你的帮助
      

  12.   

    既然知道按钮的句柄、则可用SetWindowPos设置它的位置来实现控件的移动、
    如果按钮是在面板上、则Panel的句柄也是需要的、可用GetParent取得(或者EnumChildWindows函数)、取得
    目标面板的句柄后、用SetParent把按钮移到面板上(SetParent(button.handle, panel.handle)、再进行调整位置:
    SetWindowPos(button.handle, HWND_TOP, 10, 10, 0, 0, SWP_NOSIZE);//X,Y:位置;
    SWP_NOSIZE屏蔽cx,cy参数
      

  13.   

    SetParent可能需要这样调用WINDOWS.SetParent
      

  14.   

    可以去理解一下WINDOWS关于OLE拖放实现的思想,诸如IDataObject等.
    在GOOGLE里面搜索应该有一些..
      

  15.   

    to 12rain(中雨~百年孤独)
    Panel的句柄不一定能拿到的
    首先我的程序是去控制别人的程序
    Panel也是别人程序的Panel
    我用EnumChildWindows或GetWindow得到子窗体句柄的时候
    如果窗体上有多个Panel
    而一般开发的人对Panel都不赋任何名称的(也就是空的Caption)
    请问我该如何定位这个Panel?而且SetParent有强制性
    如果Panel不是Dockable
    控件移动到Panel上时应该是“漂浮”的
    但SetParent就会让控件变为Panel的子窗体
    这样似乎也有背用户的要求
    而且很有可能用户是把控件拖到桌面上的
    所以我一直想用SendMessage来处理就是这个原因
    只要鼠标按住控件然后移动一定的位置
    至于移动以后停留在哪里就不管了
    如果刚好在某个Panel上且该Panel是Dockable的
    那就成为该Panel的子窗体
    否则就“漂浮”着
      

  16.   

    1、
    Panel的句柄、如果Panel上有按钮或者其他控件、至少可以这样取得Panel.Handle := Windows.GetParent(Button.Hanle);不要面板的句柄也行、可设为窗体的、至少要保证按钮可移出面板
    Windows.SetParent(Button.Hanle, Form.Handle);
    SetWindowPos(Button.Hanle, HWND_TOP, 100, 150, 0, 0, SWP_NOSIZE);2、
    试了一下你的发送WM_LBUTTONDOWN、WM_MOUSEMOVE消息的、鼠标点击是可以、但无法实现移动、是否需要再处理消息?或者不发送消息、写个钩子函数、只是好象也比较麻烦、只有句柄、不知道要怎么控制位置
      

  17.   

    PS、我用SendMessage(句柄,WM_MOUSEMOVE, x,y);//其中x,y我不知道如何设置
    ----------------------------------------------------------------------
    SendMessage(Handle, WM_MOUSEMOVE, MK_LBUTTON, MakeWord(xPos, yPos));
    xPosValue of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area. yPosValue of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area. 
      

  18.   

    to 12rain(中雨~百年孤独) 
    1.
    Panel的句柄是未知的,正是因为窗体上有多个Panel,而且是别人写的程序,是不确定的,Panel上的控件也是不确定的,所以不能根据Panel上的控件去定位Panel;2.
    SetParent是不可行的,因为如果窗体不支持拖放,控件应该是“漂浮”在窗体上面,而不是强制设置为窗体的子窗体;3.
    之所以用消息处理,是因为用户对控件的拖放也是不确定的,用户不一定想拖放到某个Panel上,只是想拖到某个位置,如果该位置刚好有Panel或其他容器,而且支持拖放,那该控件就刚好成为Panel或容器的子窗体;4.
    我现在遇到的难点也就是鼠标移动消息不成功,我一直在找资料研究分析中;5.
    钩子函数我试过了,不过只能针对一个程序,而且也要发送消息来处理;问题是,我的程序是用来控制用户的程序的,用户的程序也是不定的,而且开发的语言也是不定的,那样钩子函数好像也不是好的解决方法;不管怎样,多谢你的帮忙,这个问题解决了,一定要开帖庆祝!