窗体间相互连动
设其中一个为主窗体,另一个为子窗体。 在Delphi程序设计中,窗体(Form)的Position特性取值为poDesigned,则窗体的显示位置和大小以特性Left、Top、 Width、Height的取值为依据来决定。这样在创建子窗体时,以获得主窗体的显示位置和大小(主窗体的Left、Top、Width、Height 的特性值)为基准,然后确定子窗体的位置和大小即可。窗体的初始显示位置,可用CreateParams方法进行设置,之后用重载子窗体(Form1)的CreateParams方法,来改变子窗体的显示位 置和大小。主窗体和子窗体之间是怎样互相引用的呢?首先设置窗体(Form1)的单元文件名为unit1.pas,子窗体(Form2)的单元文件名为 unit2.pas。通常要引用某窗体单元文件的特性和内容时,应该在interface的uses处插入其窗体(Form)的单元名(unit)。本实 例中根据主窗体动态生成子窗体,因此在主窗体(Form1)的interface的uses处插入子窗体的单元名(unit2)。这样主窗体即可引用子窗 体的各种特性值。另一方面要实现子窗体引用主窗体的各种特性值又怎么办呢?由于Pascal语言不允许相互循环引用,即A到B,并且B到A。这时,必须在 imptementation的uses处插入主窗体的单位名(unit1),这样即可对主窗体(Form1)的特性值进行引用。
引用方法如下:
implementation
{$R *.DFM}
uses Unit1;//主窗体单元名
{生成窗体时参考数的初始化}
procedure TForm2.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
//当没有窗体题目时,添加细框
if BorderStyle = bsNone then
Params.Style := Params.Style or WS_THICKFRAME;
//根据主窗体的显示位置和大小决定子窗体的显示位置和大小
with Form1 do
begin
Params.X := Left + Width;
Params.Y := Top;
Params.Height := Height;
Params.Width := 100;
end;
end;
这样即完成了对应主窗体的子窗体在其右侧显示的程序设计。现在当我们移动主窗体时,子窗体并不随之移动,自然,移动子窗体时,主窗体也不会移动。虽然通常的Windows的应用程序则到此为止,但是我们的主题是要讨论连动,下面我们继续介绍这一问题。
首先要搞清楚,怎样把握自身窗体的移动和大小变化。在窗体的移动和大小变化时Windows系统要送出WINDOWSPOSCHANGED消息,为了捕捉此消息,对以下方法(Method)进行说明:
type
Tform1 = class(Tform)
protected
procedure WMWindowPosChanged(vax Msg:TWMWindowPosChanged);
message WM_WINDOWPOSCHANGED;
WM_WINDOWPOSCHANGED消息是在窗体的位置和大小变化后送出的。上面是对WM_WONDOWPOSCHANGED消息句柄的说明,接着是TWMWindowsPosChanged消息记录型和TWindowPos记录内容的定义。
type
TWMWindowPosMsg = record
Msg:Cardind;
Unused:Integer;
WindowPos:PwindowPos;
Resukt:Longint;
end;
PwindowPos = ∧TWindowPos;
TwindowPos = packed record
hwnd:HWND; //自身的窗体句柄
hwndInsertAfeer:HWND;//变更Z的顺序时,最上层窗体句柄
x:Integer//新窗体左端的位置
y:Integer//新窗体上端的位置
cx:Integer//新窗体上端的宽
cy:Integer//新窗体上端的高
flags:UINT//变更内容(移动、大小 、Z顺序等)
end;
下面具体介绍此方法的使用,首先要确认子窗体是否存在,而后确认自身的显示位置,一旦发生变更就使用WindowSAPI的SetWindowPos,以变更子窗体的显示位置和大小。要注意的是只是主窗体发生变更时才使用。
这样即可使子窗体随主窗体的变更而变更。接着我们还希望主窗体随子窗体的变更而变更。以下先是主窗体变更使子窗体变更的处理过程。
const
uFlag = SWP_NOACTIVATE or SWP_NOZORDER or SWP_NOMOVE orSWP_NOSIZE;
//大小变更、位置移动结束通知
porcedure TForm1.WMWindowPosChanged(var Msg:TWMWindowPosChanged);
var Rect:TRect;
x,y,cx,cy:Integer;
uFlag2:UINT;
begin
inherited;
if Form2 <> nil then
//如果子窗体存在
begin
GetWindowRoct(Form2.Handle,Rect); //获取子窗体的位置
With Msg do
begin
x:= WindowPos^.x + WindowPos^.cx; //新x坐标
y:= Window^.y; //新y坐标
cx:= 100; //宽固定在100
cy:= WindowPos^.cy //新高度
end;
uFlag2:= uFlag; //需要移动时
if(Rect.Top <> Y) or(Rect.Left<>X) then
uFlag2:= uFlag2 and(not SWP_NOMOVE);
if(Rect.Bottom -Rect.Top <>cy) or
//需要变更大小时
(Rect.Right -Rect.Left<>cx) then
uFlag2:= uFlag2 and(not SWP_NOSIZE);
if uFlag <> uFlag2 then
//对子窗体(Form)进行变更
setWindowPos(Form2.Handle,0,x,y,cx,cy,uFlag2);
以上处理是从主窗体的新位置来计算子窗体的新位置,然后与现
没有评论:
发表评论