动态移动form上任意控件 (100分)

  • 主题发起人 主题发起人 savenight
  • 开始时间 开始时间
S

savenight

Unregistered / Unconfirmed
GUEST, unregistred user!
unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;

var
Form1: TForm1;
c:tcontrol;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
a:tpoint;
begin
getcursorpos(a);
a:=screentoclient(a);
a.x:=a.X +1;
a.Y :=a.Y+1;
[gold]c:=form1.ControlAtPos(a,false,false);[/gold]
[red]c.refresh;[/red] 出错
end;
end.
-----------------------------------------------
[gold]c:=form1.ControlAtPos(a,false,false);[/gold]
这一行其实没有得到所要的TCONTROL,即 c为NIL.
我意图是动态移动form上任意控件.
[?]
 
[:D]用releasecapture的,具体查查以前的帖子
 
1.如果你的空件不是直接放在窗口上,而是放在其它容器空件(如Panel)上的,
ScreenToClient和ControlAtPos都必须指定容器控件
2.ControlAtPos(a,false,false); 改为 ControlAtPos(a,false,TRUE);
3.为何不直接用Sender,你总不会要求用户先把鼠标放到某个控件上,再用键盘去按Button1吧
 
龙丹:
1:是直接在FORM上。
2:不行。
3:我用SENDER是没有问题。
wangxd:
我用的就是SETCAPTURE,RELEASECAPTURE。
 
c.refresh 改为 application.processmessage 就可以了。
 
靠靠靠,我试了一下,TLabel 可以,TButton 不行,好奇怪啊,
看了好多代码才明白,
ControlAtPos(a,false,false); 得改为 ControlAtPos(a,true,TRUE);

因为 button 按下的时候是 disable 的,5555555~~~~~~~~~

这 100 分不好的啊


 
这就是不看帮助的结果!就看看函数的参数名字也应该知道的啊:
function ControlAtPos(const Pos: TPoint; AllowDisabled: Boolean, AllowWinControls:Boolean=False): TControl;
 
龙丹兄是不是理解错了
我的意思是说 Enabled 的 TButton 按下的时候是 Disable 的,
这一点帮助上我没看到过
 
没表达清楚,应该是 vcl 内部是按 disable 来处理的
 
这就有点怪了!我的程序用ControlAtPos(a,false,TRUE)没有问题呀,不过Button是在
PageControl的TabSheet里,待会直接放在窗口再试试
 
procedure TDemoMainForm.Button20Click(Sender: TObject);
var
a:tpoint;
c:TControl;
begin
getcursorpos(a);
a:={TabSheet8.}Screentoclient(a);
Edit5.Text:=Format('(%d,%d)',[a.x,a.y]);
c:={TabSheet8.}ControlAtPos(a,false,True);
if c<>nil then
begin
c.refresh;
Edit5.Text:=Edit5.Text+c.Name;
end;
end;
也没有问题呀,Edit5.Text显示为:(176,207)Button20
 
龙丹兄用的是 delphi 几?

你可以看看 ControlAtPos 得源码:

function TWinControl.ControlAtPos(const Pos: TPoint; AllowDisabled,
AllowWinControls: Boolean): TControl;
var
I: Integer;
P: TPoint;
LControl: TControl;
function GetControlAtPos(AControl: TControl): Boolean;
begin
with AControl do
begin
P := Point(Pos.X - Left, Pos.Y - Top);
Result := PtInRect(ClientRect, P) and
((csDesigning in ComponentState) and (Visible or
not (csNoDesignVisible in ControlStyle)) or
(Visible and (Enabled or AllowDisabled) and
(Perform(CM_HITTEST, 0, Longint(PointToSmallPoint(P))) <> 0)));
if Result then
LControl := AControl;
end;
end;
begin
LControl := nil;
if AllowWinControls and
(FWinControls <> nil) then
for I := FWinControls.Count - 1 downto 0 do
if GetControlAtPos(FWinControls) then
Break;
if (FControls <> nil) and
(LControl = nil) then
for I := FControls.Count - 1 downto 0 do
if GetControlAtPos(FControls) then
Break;
Result := LControl;
end;

AllowWinControls 参数对结果应该没有影响的,只是加快了速度而已
 
从 ControlAtPos 来看,关键还是 AllowDisabled

PtInRect(ClientRect, P) and ((csDesigning in ComponentState) and (Visible or not (csNoDesignVisible in ControlStyle)) or (Visible and (Enabled or AllowDisabled) and (Perform(CM_HITTEST, 0, Longint(PointToSmallPoint(P))) <> 0)))
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ ~~~~~~~ ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
true and ( false and (true or 无关紧要 ) or ( true and ( Enabled or AllowDisabled) and true))


true and (false and (true or 无关紧要) or (true and (Enabled or AllowDisabled) and true))
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
true and (false and true or (Enabled or AllowDisabled))

(Enabled or AllowDisabled) 是最后结果

 
怪事了,我现在又可以了,糊涂了~~~~~~~~~[:(]
 
我用的Delphi5,打过几个补丁,你呢?从你贴的代码看来,与我的有点区别:变量名不同LControl - vControl
AllowWinControls 对结果是绝对有影响的(改变这个参数一运行就知道了),这是因为
FControls和FWinControls是整个Controls的划分,参考GetControlCount方法
 
(Enabled or AllowDisabled) 应该不会返回False,如果按钮按下去自己就变成Enabled=False的话,应该早就有人骂娘了
 
对不起,可能是我的意思没表达清楚。[:)]
还是把代码贴完整吧:
代码:
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Label1: TLabel;
    Memo1: TMemo;
    procedure Button1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Button1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Button1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    MouseDownSpot:tpoint;
    capturing:bool;
  end;

var
  Form1: TForm1;
  c:tcontrol;
implementation

{$R *.dfm}

procedure TForm1.Button1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
  var
  a:tpoint;
begin
 if ssctrl in shift then begin
 a.X :=x;
 a.Y :=y;
 setcapture(windowfrompoint(a));
 [b][red]c:= form1.controlatpos(a,true,true);[/red][/b]
//这里 true,false都一样的结果
 capturing:=true;
 MouseDownspot.X :=x;
 mousedownspot.Y :=y;
 end;
end;

procedure TForm1.Button1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 if capturing then
begin
 releasecapture;
 capturing:=false;
 c.Left :=c.Left-(mousedownspot.X-x);
 c.top :=c.top -(mousedownspot.y-y);
 end;
end;

procedure TForm1.Button1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
if capturing=true then
begin
 c.Left :=c.Left -(mousedownspot.X-x);
 c.top :=c.top -(mousedownspot.y-y);
 end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
c:=tcontrol.Create(self);
end;

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

end.
 
昨天怎么不贴这代码?
a.X :=x; --> a.X := x+TControl(Sender).Left;
a.Y :=y; --> a.Y := y+TControl(Sender).Top;
不过你这一折腾,倒是让940801和我把ControlAtPos的代码读了个透彻!
 
原来x,y是相对于 button等控件的.
多谢龙丹,也谢谢 940801.
两位若原交个朋友的话。。。
QQ:27722635
[:)]
 
后退
顶部