MDI窗体怎么知道子窗体的建立和切换?(100分)

  • 主题发起人 主题发起人 gondsoft
  • 开始时间 开始时间
G

gondsoft

Unregistered / Unconfirmed
GUEST, unregistred user!
MDI窗体中会有事件触发吗?
用什么方式可以解决这问题呢?
 
检查ActiveChildForm属性, 该属性指向当前活动的子窗口
 
1.在主窗体的WindowMenu设置位置显示当前活动的子窗口.
2.使用ActiveChildForm,MDIChildCount,MDIChildForm来判断
3.拦截ClientWindow的消息.(详见Delphi开发人员手册)
 
借用宝地一问:
如有两个子窗体form1和form2,在打开form1时如果form2存在则关闭它,反之亦然,该如何做,谢谢。
 
to wzdcli
我认为必须通过拦截ClientWindow的消息(获得子窗体产生的消息)来处理
 
//看一下吧:
function ChildProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
Result := CallWindowProc(Pointer(GetWindowLong(hWnd,GWL_USERDATA)),
hWnd, Msg, wParam, lParam);
Case Msg of
WM_NCACTIVATE:
if wParam >0 then SetWindowText(hWnd, PChar(FormatDateTime('HH:MM:SS',Now)));
end;
end;

function ClientProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
h : Thandle;
begin
Result := CallWindowProc(Pointer(GetWindowLong(hWnd,GWL_USERDATA)),
hWnd, Msg, WPARAM, lParam);
Case Msg of
WM_MDICREATE:
with TMDICreateStruct(Pointer(lParam)^) do
begin
h := FindWindowEx(hWnd, 0, szClass, szTitle);
if h > 0 then
begin
SetWindowLong(h,GWL_USERDATA,GetWindowLong(h,GWL_WNDPROC));
SetWindowLong(h,GWL_WNDPROC,LongInt(@ChildProc));
end;
end;
end;
end;

procedure TMDIMain.FormCreate(Sender: TObject);
begin
SetWindowLong(ClientHandle,GWL_USERDATA,GetWindowLong(ClientHandle,GWL_WNDPROC));
SetWindowLong(ClientHandle,GWL_WNDPROC,LongInt(@ClientProc));
end;
 
还有一种方法,就是你在做这些建立或切换时,通知MDI也中呀?
 
楼上的几位高手,我是新手,对API不熟悉,能给我说一下这几个函数的意思或如何拦截ClientWindow的消息吗?谢谢
 
详见Delphi5开发人员手册中有例子的
 
你干脆先关闭全部窗口,然后在打开单个窗口好了
for i:=0 to MDIChildCount-1 do
self.MDIChildren.Close
 
>>amli,
我不清楚你的意思是什么,是在Forms单元中的DELPHI定义吗?
代码SetWindowLong(ClientHandle,GWL_WNDPROC,LongInt(@ClientProc));中的
ClientProc是什么定义呢?
 
//MDIMain(主窗口名字(Name=MDIMain,可以是其它的)
//這兒按上邊寫代碼
//ChildProc 當前子窗口收到所有消息都會執行到
//ClientProc 當前客戶窗口收到所有消息都會執行到
procedure TMDIMain.FormCreate(Sender: TObject); //主窗口創建事件
begin
//初始化客戶窗口的窗口過程,再客戶窗口負責初始化子窗口的窗口過程
end;
 
其实DELPHI将普通的FORM变成MDIForm,是在FORM的CreateWnd事件中仅以下面的代码实现:
FClientHandle := Windows.CreateWindowEx(WS_EX_CLIENTEDGE, 'MDICLIENT',
nil, WS_CHILD or WS_VISIBLE or WS_GROUP or WS_TABSTOP or
WS_CLIPCHILDREN or WS_HSCROLL or WS_VSCROLL or WS_CLIPSIBLINGS or
MDIS_ALLCHILDSTYLES, 0, 0, ClientWidth, ClientHeight, Handle, 0,
HInstance, @ClientCreateStruct);
它是调用Windows的API函数创建的window,FClientHandle 就是这个Window的句柄。这个窗口就是MDIForm窗口中可以看到的那块区域,这块区域显示所有的子窗体,并可排列(水平平铺,重排列)这些子窗体。

但这些子窗体在创建或子窗体间的切换时,都是向FClientHandle句柄发送API消息。如如下代码:
function TCustomForm.GetActiveMDIChild: TForm;
begin
...
SendMessage(FClientHandle, WM_MDIGETACTIVE, 0, 0);//将返回当前的子窗体句柄
...
end;

 
第一步:在Form1的Private中定义:
FClientInstance,
FPrevClientProc : TFarProc;
PROCEDURE ClientWndProc(VAR Message: TMessage);
第二步:在实现(implementation)中加入上述过程的具体内容:
PROCEDURE TForm1.ClientWndProc(VAR Message: TMessage);
VAR
MyDC : hDC;
Ro, Co : Word;
begin
with Message do
case Msg of
WM_MDICREATE:
begin
...
end;
WM_MDIActive:
begin
...
end;
else
Result := CallWindowProc(FPrevClientProc, ClientHandle, Msg, wParam, lParam);
end;
end;
第三步:在Form1的创建事件中加入:
FClientInstance := MakeObjectInstance(ClientWndProc);
FPrevClientProc := Pointer(GetWindowLong(ClientHandle, GWL_WNDPROC));
SetWindowLong(ClientHandle, GWL_WNDPROC, LongInt(FClientInstance));

上面的代码是示意的,没测试
具体详见Delphi5开发人员手册
 
>>amli,yostgxf
谢谢你们啦。yostgxf的代码调试正确,但amli也有功劳了。[8D]
 
后退
顶部