鼠标拖动Panel控件改变位置为什么要先ReleaseCapture?

ooolinux 2018-06-18 08:56:40
鼠标拖动Panel控件改变位置为什么要先ReleaseCapture?
void __fastcall TForm1::Panel1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if(Button==mbLeft)
{
ReleaseCapture(); //为什么要先ReleaseCapture?
SendMessage(Panel1->Handle,WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0);
}
}
...全文
1253 29 打赏 收藏 转发到动态 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
ooolinux 2019-03-15
  • 打赏
  • 举报
回复
觉得上面的理解还是不对,我重新理解了一下,鼠标拖动Panel,就是鼠标左键按下以后移动,按下的动作会由VCL产生SetCapture调用,使Panel(有Handle属于窗口控件)捕获了鼠标消息。因此只有ReleaseCapture以后,再
SendMessage(Panel1->Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
模拟鼠标在Panel标题栏(窗口控件都有标题栏,虽然Panel看起来没有)按下,接下来的鼠标移动消息(没有被任何窗口捕获)使得,在标题栏按下加上移动鼠标,系统就处理为拖动Panel窗口(改变位置)了。
abc_ustone 2019-03-15
  • 打赏
  • 举报
回复
ooolinux 2019-03-15
  • 打赏
  • 举报
回复
我对主楼问题的理解是这样的,鼠标拖动Panel,就是鼠标左键按下以后移动,按下的动作会由VCL产生SetCapture,使Panel客户区捕获了鼠标消息,因此直接
SendMessage(Panel1->Handle,WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0);没有产生效果,如果先ReleaseCapture,再SendMessage模拟鼠标在Panel(属于窗口控件)标题栏按下,这个模拟按下代替了原来的客户区按下(偷梁换柱),以后移动鼠标就是相当于在按下标题栏的情况下移动鼠标,所以能移动Panel了。
两种SendMessage效果是一样的:
SendMessage(Panel1->Handle,WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0);
SendMessage(Panel1->Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);

老概来纠纠错~
ooolinux 2019-03-15
  • 打赏
  • 举报
回复
原来是6楼的代码不完善,忘了Memo1MouseDown。
void __fastcall TForm1::Memo1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if(CheckBox1->Checked)
ReleaseCapture();
}
修改后的代码,现在理解了:
链接:https://pan.baidu.com/s/1RiJ12GPeC1ztzvlAFUuQug
提取码:lyzc
复制这段内容后打开百度网盘手机App,操作更方便哦
ooolinux 2018-07-25
  • 打赏
  • 举报
回复
引用 22 楼 DelphiGuy 的回复:
也可能是SetCapture之后,如果不释放左键,ReleaseCapture只是清除了消息队列中的下一条WM_MOUSEMOVE消息


不是很理解~
  • 打赏
  • 举报
回复
引用 23 楼 u010165006 的回复:
[quote=引用 22 楼 DelphiGuy 的回复:]
也可能是SetCapture之后,如果不释放左键,ReleaseCapture只是清除了消息队列中的下一条WM_MOUSEMOVE消息


如果从外往内拖动就不会。。[/quote]

从外往内拖动Memo没有获得焦点,没有得到鼠标左键按下消息,此时捕获鼠标的是其他控制
ooolinux 2018-07-25
  • 打赏
  • 举报
回复
引用 22 楼 DelphiGuy 的回复:
也可能是SetCapture之后,如果不释放左键,ReleaseCapture只是清除了消息队列中的下一条WM_MOUSEMOVE消息


如果从外往内拖动就不会。。
  • 打赏
  • 举报
回复
也可能是SetCapture之后,如果不释放左键,ReleaseCapture只是清除了消息队列中的下一条WM_MOUSEMOVE消息

  • 打赏
  • 举报
回复
看代码并没有这样,但是实际效果似乎确实如此,有待研究。
ooolinux 2018-07-24
  • 打赏
  • 举报
回复
引用 20 楼 DelphiGuy 的回复:
看代码并没有这样,但是实际效果似乎确实如此,有待研究。


不知道是不是跟它是焦点控件有关。
ooolinux 2018-07-23
  • 打赏
  • 举报
回复
引用 18 楼 DelphiGuy 的回复:
[quote=引用 16 楼 u010165006 的回复:]
[quote=引用 11 楼 DelphiGuy 的回复:]
因为TMemo在鼠标左键按下时已经捕获了鼠标,从VCL源码来看,所有TWinControl在鼠标左键按下时会捕获鼠标(左键放开会释放),而非TWinControl,会由它的Parent捕获鼠标


勾选ReleaseCapture,点击自动捕获了鼠标,我的代码又ReleaseCapture了,但是从内往外拖动,鼠标无论在内还是在外,都是Edit3和Edit4显示位置变化,感觉鼠标一直被TMemo捕获的。[/quote]

如果在Memo1MouseMove事件处理中ReleaseCapture()就不会了
[/quote]

难道在TMemo里拖动每次Move一下鼠标就重新被捕获了?
  • 打赏
  • 举报
回复
引用 16 楼 u010165006 的回复:
[quote=引用 11 楼 DelphiGuy 的回复:]
因为TMemo在鼠标左键按下时已经捕获了鼠标,从VCL源码来看,所有TWinControl在鼠标左键按下时会捕获鼠标(左键放开会释放),而非TWinControl,会由它的Parent捕获鼠标


勾选ReleaseCapture,点击自动捕获了鼠标,我的代码又ReleaseCapture了,但是从内往外拖动,鼠标无论在内还是在外,都是Edit3和Edit4显示位置变化,感觉鼠标一直被TMemo捕获的。[/quote]

如果在Memo1MouseMove事件处理中ReleaseCapture()就不会了
  • 打赏
  • 举报
回复
procedure TControl.WMLButtonDown(var Message: TWMLButtonDown);
begin
SendCancelMode(Self);
inherited;
if csCaptureMouse in ControlStyle then
MouseCapture := True;
if csClickEvents in ControlStyle then
Include(FControlState, csClicked);
DoMouseDown(Message, mbLeft, []);
end;

procedure TControl.SetMouseCapture(Value: Boolean);
begin
if MouseCapture <> Value then
if Value then SetCaptureControl(Self) else SetCaptureControl(nil);
end;

procedure SetCaptureControl(Control: TControl);
begin
ReleaseCapture;
CaptureControl := nil;
if Control <> nil then
begin
if not (Control is TWinControl) then
begin
if Control.Parent = nil then Exit;
CaptureControl := Control;
Control := Control.Parent;
end;
SetCapture(TWinControl(Control).Handle);
end;
end;
  • 打赏
  • 举报
回复
因为TMemo在鼠标左键按下时已经捕获了鼠标,从VCL源码来看,所有TWinControl在鼠标左键按下时会捕获鼠标(左键放开会释放),而非TWinControl,会由它的Parent捕获鼠标

ooolinux 2018-07-20
  • 打赏
  • 举报
回复
引用 13 楼 DelphiGuy 的回复:
发现一处有趣的代码:
constructor TCustomMemo.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := 185;
Height := 89;
...
这Width、Height默认值是什么,作者的身高、体重?


有可能~
ooolinux 2018-07-20
  • 打赏
  • 举报
回复
引用 11 楼 DelphiGuy 的回复:
因为TMemo在鼠标左键按下时已经捕获了鼠标,从VCL源码来看,所有TWinControl在鼠标左键按下时会捕获鼠标(左键放开会释放),而非TWinControl,会由它的Parent捕获鼠标


勾选ReleaseCapture,点击自动捕获了鼠标,我的代码又ReleaseCapture了,但是从内往外拖动,鼠标无论在内还是在外,都是Edit3和Edit4显示位置变化,感觉鼠标一直被TMemo捕获的。
  • 打赏
  • 举报
回复
引用 14 楼 sololie 的回复:
[quote=引用 13 楼 DelphiGuy 的回复:]
发现一处有趣的代码:
constructor TCustomMemo.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := 185;
Height := 89;
...
这Width、Height默认值是什么,作者的身高、体重?


身高89,体重185 [/quote]

这是史莱克吧
sololie 2018-07-20
  • 打赏
  • 举报
回复
引用 13 楼 DelphiGuy 的回复:
发现一处有趣的代码:
constructor TCustomMemo.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := 185;
Height := 89;
...
这Width、Height默认值是什么,作者的身高、体重?


身高89,体重185
  • 打赏
  • 举报
回复
发现一处有趣的代码:
constructor TCustomMemo.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := 185;
Height := 89;
...
这Width、Height默认值是什么,作者的身高、体重?
  • 打赏
  • 举报
回复
VCL中的TControl确实在某些情况下捕获了鼠标:
Vcl.Controls.Pas:
procedure TControl.WMLButtonDown(var Message: TWMLButtonDown);
begin
SendCancelMode(Self);
inherited;
if csCaptureMouse in ControlStyle then
MouseCapture := True;

if csClickEvents in ControlStyle then
Include(FControlState, csClicked);
DoMouseDown(Message, mbLeft, []);
end;

TControl的派生类TForm、TFrame、TScrollBox都包含控制风格csCaptureMouse
加载更多回复(9)

1,221

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧