有礼了!问一个技术技巧的问题:怎样让窗体跟随鼠标移动?? - 我写不正确! :( (200分)

  • 主题发起人 主题发起人 本公子
  • 开始时间 开始时间

本公子

Unregistered / Unconfirmed
GUEST, unregistred user!
检索了一下,发现以前只有一个这样的问题,还没有给出答案:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=632407
---
我写的如下:
var
Form1: TForm1;
w,h:integer;
implementation

{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
w:= Width;
h:= Height;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
p:Tpoint;
hwnd:integer;
Rec:hrgn;
begin
GetCursorPos(p);
p:=ScreenToClient(p);

hwnd:=Handle;
Rec:=createRectRgn(p.x,p.Y,w,h); //生成窗口范围
setwindowRgn(hwnd,Rec,true);
end;

运行后,但是和想像中的不一样,画不出窗体。
难到用setwindowRgn不对吗?

OnMousemove可以排除在外,因为光标不在窗体上滑动。

后来不用Timer了,改成用ApplicationEvents---
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
begin
Form1.Left:=Msg.pt.X;
Form1.Top:=Msg.pt.Y;
end;
运行后,向右下方托动鼠标时,窗体勉强可以跟随,但是左上移动鼠标没有反应。 何故?
有什么方法可以解决这个问题?
用HOOK可以吗? 那位大哥做过这个? 或知道方法或相关代码?

我知道DFW人气很旺的,给点提示吧! 谢谢! 初来乍到奉送200分先。
 
如果要鼠标按下才能动的话,这样可以。
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
releasecapture;
perform(wm_syscommand,$f012,0);
end;
 
我也来学习学习!
 
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;

type
TForm1 = class(TForm)
Panel1: TPanel;
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Timer1Timer(Sender: TObject);
begin
Left:=Mouse.CursorPos.x;
Top:=Mouse.CursorPos.y;
end;

end.

不过用TTimer是一个笨办法,性能很差;
用ApplicationEvents也不行,因为只有鼠标在窗口范围内移动才会用有消息发送到应用程序,
最好用HOOK,关于鼠标HOOK的文章很多,我的主页http://www.aidelphi.com上就有我做的一段源码例子.
 
to jbas:
按下鼠标也是在窗体范围内有效 窗体外无效 谢谢!
to aizb:
多谢大哥!
我曾这样试过:
GetCursorPos(p);
p:=ScreenToClient(p);
Left:=P.x;
Top:=P.y;
闪烁的太厉害 不过你的很好 不闪烁 我去你的主页上看看
 
你还可以用线程的方法,专们用一个线程来跟踪鼠标,不过性能还是没有用HOOK好:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;

type
TMyThread = class(TThread)
private
FForm:TForm;
procedure ReposForm;
protected
procedure Execute; Override;
public
constructor Create(Form:TForm;CreateSuspended: Boolean);
end;

TForm1 = class(TForm)
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FMyThread:TMyThread;
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

{ TMyThread }

procedure TMyThread.ReposForm;
begin
FForm.Left:=Mouse.CursorPos.x;
FForm.Top:=Mouse.CursorPos.y;
end;

procedure TMyThread.Execute;
begin
while not Terminated do
Synchronize(ReposForm);
end;

constructor TMyThread.Create(Form: TForm; CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
FForm:=Form;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
FMyThread:=TMyThread.Create(Self,False);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
FMyThread.Free;
end;

end.
 
to aizb:
多谢大哥劳神!
启用线程后的确是平滑多了。
 
这个用hook实现,你看看吧,我是改自我的一个涂鸦程序,你可以去掉好多没用的东西。
unit tymain;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, ExtCtrls;

type
TForm1 = class(TForm)
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
GroupBox1: TGroupBox;
GroupBox3: TGroupBox;
SpeedButton3: TSpeedButton;
Panel1: TPanel;
Image1: TImage;
Panel2: TPanel;
Panel3: TPanel;
SpeedButton4: TSpeedButton;
Panel4: TPanel;
Panel5: TPanel;
Panel6: TPanel;
Panel7: TPanel;
Panel8: TPanel;
procedure SpeedButton1Click(Sender: TObject);
procedure SpeedButton2Click(Sender: TObject);
procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure Image1DblClick(Sender: TObject);
procedure SpeedButton3Click(Sender: TObject);
procedure Panel2DblClick(Sender: TObject);
procedure Image1Click(Sender: TObject);
procedure SpeedButton4Click(Sender: TObject);
procedure Panel5Click(Sender: TObject);
procedure Panel6Click(Sender: TObject);
procedure Panel7Click(Sender: TObject);
procedure Panel8Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
pencolor:tcolor;
mycanvas:tcanvas;
screendc:hdc;
pensize,hook,mm:integer;
can:boolean=false;

implementation
{$R *.dfm}
{$R mycursor.res}

function hookproc(icode:integer;wparam:wparam;lparam:lparam):lresult;stdcall;
var
evtmsg:teventmsg;
begin
evtmsg:=peventmsg(lparam)^;
form1.Left:=mouse.CursorPos.X; ///////这里被改动了,你也可以改的更精确。
form1.Top:=mouse.CursorPos.Y; ///////
if evtmsg.message=WM_LBUTTONDOWN then
begin
can:=true;
mycanvas.moveto(mouse.CursorPos.X,mouse.CursorPos.Y);
end;
if evtmsg.message=WM_LBUTTONUP then
can:=false;
if can=true then
begin
if evtmsg.message=WM_MOUSEMOVE then
begin
with mycanvas do
begin
Pen.Color:=form1.Panel1.Color;
lineto(mouse.CursorPos.X,mouse.CursorPos.Y);
end;
end;
end;
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
screendc:=getdc(0);
mycanvas:=tcanvas.Create;
mycanvas.Handle:=screendc;
end;

procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
InvalidateRect(0, nil, true);
close;
end;

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
pencolor:=image1.Picture.Bitmap.Canvas.Pixels[X,Y];
panel3.Color:=pencolor;
end;

procedure TForm1.Image1DblClick(Sender: TObject);
var
colordial:tcolordialog;
begin
colordial:=tcolordialog.Create(self);
colordial.Color:=pencolor;
colordial.Execute;
panel2.Color:=colordial.Color;
end;

procedure TForm1.SpeedButton3Click(Sender: TObject);
var
scr:hicon;
begin
panel2.SetFocus;
scr:=loadcursor(hinstance,'mycur');
setsystemcursor(scr,ocr_normal);
mycanvas.Pen.Color:=panel1.Color;
hook:=setwindowshookex(WH_JOURNALRECORD,hookproc,hinstance,0);
end;

procedure TForm1.Panel2DblClick(Sender: TObject);
var
mycolor:tcolordialog;
begin
mycolor:=tcolordialog.Create(self);
mycolor.Color:=panel2.Color;
mycolor.Execute;
panel2.Color:=mycolor.Color;
end;



procedure TForm1.Image1Click(Sender: TObject);
begin
panel2.Color:=panel3.Color;
end;

procedure TForm1.SpeedButton4Click(Sender: TObject);
begin
systemparametersinfo(spi_setcursors,0,nil,spif_sendchange);
unhookwindowshookex(hook);
end;

procedure TForm1.Panel5Click(Sender: TObject);
begin
pensize:=panel5.Height;
if panel5.BorderStyle=bssingle then
begin
panel5.BorderStyle:=bsnone;
panel5.BevelInner:=bvnone;
panel5.BevelOuter:=bvnone;
end
else
begin
panel5.BorderStyle:=bssingle;
panel5.BevelInner:=bvlowered;
panel5.BevelOuter:=bvraised;
end;
end;

procedure TForm1.Panel6Click(Sender: TObject);
begin
pensize:=panel6.Height;
if panel6.BorderStyle=bssingle then
begin
panel6.BorderStyle:=bsnone;
panel6.BevelInner:=bvnone;
panel6.BevelOuter:=bvnone;
end
else
begin
panel6.BorderStyle:=bssingle;
panel6.BevelInner:=bvlowered;
panel6.BevelOuter:=bvraised;
end;
end;

procedure TForm1.Panel7Click(Sender: TObject);
begin
pensize:=panel7.Height;
if panel7.BorderStyle=bssingle then
begin
panel7.BorderStyle:=bsnone;
panel7.BevelInner:=bvnone;
panel7.BevelOuter:=bvnone;
end
else
begin
panel7.BorderStyle:=bssingle;
panel7.BevelInner:=bvlowered;
panel7.BevelOuter:=bvraised;
end;
end;

procedure TForm1.Panel8Click(Sender: TObject);
begin
pensize:=panel8.Height;
if panel8.BorderStyle=bssingle then
begin
panel8.BorderStyle:=bsnone;
panel8.BevelInner:=bvnone;
panel8.BevelOuter:=bvnone;
end
else
begin
panel8.BorderStyle:=bssingle;
panel8.BevelInner:=bvlowered;
panel8.BevelOuter:=bvraised;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
screendc:=getdc(0);
mycanvas:=tcanvas.Create;
mycanvas.Handle:=screendc;
end;

end.
 
pos:TPos;
procedure WMFormMove(var msg:TMessage);message WM_MOVING ;

procedure TForm1.WMFormMove(var msg:TMessage);
var
i:integer;
begin
inherited;
for i:=0 to Screen.FormCount-1 do //遍历程序所有显示的窗口
begin
//发现有显示的窗口而且不是自己的窗口就做以下
if (Screen.CustomForms.visible=true) and (Screen.CustomForms<>self) then
begin
//如果该窗口在自己傍边或者是下面就设置其的LEFT和TOP属性
// if Screen.CustomForms.top=self.top+self.Height then
// begin
case pos of
caButtom:SetWindowPos(Screen.CustomForms.Handle,
HWND_BOTTOM,
self.Left,
self.Top+self.Height,
Screen.CustomForms.width,
Screen.CustomForms.height,
SWP_DEFERERASE);


caLeft :SetWindowPos(Screen.CustomForms.Handle,
HWND_BOTTOM,
self.Left-Screen.CustomForms.width,
self.Top,
Screen.CustomForms.width,
Screen.CustomForms.height,
SWP_DEFERERASE);

caTop :SetWindowPos(Screen.CustomForms.Handle,
HWND_TOP,
self.Left,
self.Top-Screen.CustomForms.height,
Screen.CustomForms.width,
Screen.CustomForms.height,
SWP_DEFERERASE);

// end;

// if Screen.CustomForms.Left=self.left+self.Width then
// begin

caRight:SetWindowPos(Screen.CustomForms.Handle,
HWND_TOP,self.Left+self.Width,
self.Top,
Screen.CustomForms.width,
Screen.CustomForms.height,
SWP_DEFERERASE);


end;
end;
end;
Msg.Result:=0;

end;
 
这是原理,很容易看懂,你稍做修改就可以用了[:D]
 
多谢无忌大哥呀!
原理是看明白了。
可是TPos是怎么定义的?要引用那个单元?
 
难到我的那个hook不行吗?
 
TPos=(caTop,caLeft,caButtom,caRight);
case RadioGroup1.ItemIndex of
0:pos:=caTop;
1:pos:=caButtom;
2:pos:=caLeft;
3:pos:=caRight;
end;
这个是我自己定义的枚举类型
 
to jbas:老兄 hook当然可以
to 张无忌:我把代码修改了一下,做成子窗体跟随主窗体移动的!(是Form和Form的 ,不是鼠标)
向周围窗体发送消息,可以跟随主窗体移动,加上磁性,就像Winmap的窗体一样移动
不过感觉移动效果不是太好!没有窗体“整合移动”的感觉
 
多谢楼上各位!
结贴送分了!
 
后退
顶部