TMovePanel

类别:编程语言 点击:0 评论:0 推荐:

两个老生常谈的问题:
  1、如何实现鼠标点住客户区拖动窗体?如何移动没有标题栏的窗体?
  2、如何在程序运行期间用鼠标拖动窗体上的控件?

在我这里,这两个问题是这样解决的——

--------------------------------------------------------------------------------
★ 拖动窗体 ★
  经典的做法:"欺骗"系统,让它以为点中的是窗体的标题栏
type
  TForm1 = class(TForm)
  ……
  private
   procedure WMNCHitTest(var M: TWMNCHitTest); message wm_NCHitTest;
end;

var
  Form1: TForm1;
implementation

procedure TForm1.WMNCHitTest(var M: TWMNCHitTest);
begin
  inherited;           //call the inherited message handler
  if M.Result := htClient then   //is the click in the client area?
  M.Result := htCaption;     //if so, make Windows think it's on the caption bar.
end;

 

------------------------------------------------------------------------------------------
  这种做法看似巧妙,但实际上有缺陷,你会发现,窗体的客户区不可能向上移出屏幕。再来,把下面的代码做成一个控件,精彩的还在后面——
------------------------------------------------------------------------------------------

unit MovePanel;
interface
uses
 Windows, Classes, Controls,ExtCtrls;
type
 TMovePanel = class(TPanel)  //这个控件是继承Tpanel类的
 private
  PrePoint:TPoint;
  Down:Boolean;
  { Private declarations }
 rotected
  { Protected declarations }
 public
  onstructor Create(AOwner:TComponent);override;
   //重载鼠标事件,抢先处理消息
  procedure MouseDown(Button: TMouseButton;
    Shift: TShiftState; X, Y: Integer);override;
  procedure MouseUp(Button: TMouseButton;
    Shift: TShiftState; X, Y: Integer);override;
  procedure MouseMove(Shift: TShiftState;X, Y: Integer);override;
  { Public declarations }
 published
 { Published declarations }
 end;

procedure Register;

implementation

constructor TMovePanel.Create(AOwner:TComponent);
begin
 inherited Create(AOwner); //继承父类的Create方法
end;

procedure TMovePanel.MouseDown(Button:
  TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
 if (Button=MBLeft) then begin
  Down:=true;
  GetCursorPos(PrePoint);
 end;
  //如果方法已存在,就触发相应事件去调用它,若不加此语句会造成访存异常
 if assigned(OnMouseDown) then
  OnMouseDown(self,Button,shift,x,y);
end;

procedure TMovePanel.MouseUp(Button:
  TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
 if (Button=MBLeft) and Down then
  Down:=False;
 if assigned(OnMouseUp) then
  OnMouseUp(Self,Button,shift,X,y);
end;

procedure TMovePanel.MouseMove(Shift:
  TShiftState; X, Y: Integer);
Var
  NowPoint:TPoint;
begin
 if down then begin
  GetCursorPos(nowPoint);
//self.Parent在Form中就是MovePanel所在的窗体,或是MovePanel所在的容器像Panel
  self.Parent.Left:=self.Parent.left+NowPoint.x-PrePoint.x;
  self.parent.Top:=self.Parent.Top+NowPoint.y-PrePoint.y;
  PrePoint:=NowPoint;
 end;
 if Assigned(OnMouseMove) then
  OnMouseMove(self,Shift,X,y);
end;

procedure Register;
begin
 RegisterComponents('Md3', [TMovePanel]);
end;

end.

---- 接下来,看看怎么用它吧。
---- 用法一:拖一个Form下来,加上我们的MovePanel,Align属性设为alClient,运行一下,移动窗体的效果还不错吧!想取消此功能,把MovePanel的Enabled属性设为False即可,简单吧!

---- 用法二:拖一个Form下来,加上普通的Panel,调整好大小,再在Panel上加上MovePanel, Align属性设为alClient,运行一下,这一次在我们拖动MovePanel时不是窗体在移动,而是Panel和MovePanel一起在窗体上移动,如果我们再把其他的控件放在MovePanel上,就成了可以在窗体上任意移动的控件了,就这么简单!

(原作者:福州大学 王骏)


 达到要求了吗?好像是的。再苛刻点儿,要求包括窗体在内的每一个控件都可以独立地用鼠标点住拖动,又该怎么办?

 

★ 移动控件! ★

在一个新的Form中放入一个Panel,加入如下代码:

procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton; Shift:  TShiftState; X, Y: Integer);
const
 SC_DragMove = $F012; // a magic number
begin
 ReleaseCapture;
 panel1.perform(WM_SysCommand, SC_DragMove, 0);
end;

试试就知道了,你想怎么拖就怎么拖!这个方法很不错!在拖动单个控件时非常有效。
MovePanel源代码:910字节 总结:一般情况下用MovePanel就够了,如果还要拖动单个控件,就再用上面最后一种方法,只要控件可以响应MouseDown事件就可以用! 

发表于“阿甘的家”
2000年8月18日

本文地址:http://com.8s8s.com/it/it27376.htm