MDI应用程序分三个部分:框架窗口(Frame Window),客户窗口(Client Window),子窗口(Child Window) ,在VCL中,这个Client Window已经被封装了,你不能直接使用消息映射或者Application.OnMessage来得到发送到Client Window的消息,所以须在启动时使用SetWindowLog更改客户窗口的默认消息处理过程,在程序退出时恢复.
.h
...
private:
void __fastcall ClientProc(TMessage &msg);
Pointer ClientObjInstance;
LONG OldClientProc;
...
.cpp
...
void __fastcall TForm1::FormCreate(TObject *Sender)
{
ClientObjInstance = MakeObjectInstance(ClientProc);
OldClientProc = SetWindowLong(ClientHandle,GWL_WNDPROC,(long)ClientObjInstance);
}
void __fastcall TForm1::FormClose(TObject *Sender)
{
SetWindowLong(ClientHandle,GWL_WNDPROC,OldClientProc);
FreeObjectInstance(ClientObjInstance);
}
//下面函数用来讲子窗体列表加入到ListBox1中,记得在最后调用默认的ClientWindow处理过程
void __fastcall TForm1::ClientProc(TMessage &msg)
{
if (msg.Msg == WM_PARENTNOTIFY) {
if (msg.WParamLo == WM_CREATE) {
TForm *r = (TForm *)(FindControl((HWND)msg.LParam));
ListBox1->Items->AddObject(r->Caption,r);
}
else if (msg.WParamLo == WM_DESTROY) {
TForm *r = (TForm *)(FindControl((HWND)msg.LParam));
ListBox1->Items->Delete(ListBox1->Items->IndexOfObject(r));
}
}
msg.Result = CallWindowProc((FARPROC)OldClientProc,
ClientHandle,msg.Msg,msg.WParam,msg.LParam);
}
//点击ListBox激活相应子窗体
void __fastcall TForm1::ListBox1Click(TObject *Sender)
{
TForm *AForm = (TForm *) ListBox1->Items->Objects[ListBox1->ItemIndex];
if (AForm->WindowState == wsMinimized)
SendMessage(AForm->Handle,WM_SYSCOMMAND,SC_RESTORE,0);
AForm->BringToFront();
}
WM_PARENTNOTIFY是子窗体向ClientWindow发送的消息,使用参数WParamLo判定事件,详情看帮助,如果使用WM_MDICREATE和WM_MDIDESTROY也是可以的,但是要注意调用默认过程CallWindowProc的顺序,因为WM_MDICREATE在处理之后才会返回子窗体句柄,而WM_MDIDESTROY则必须在处理之前使用它的WParam参数作为子窗体句柄.