分类: C/C++
2008-05-31 09:23:26
form->Show();
Chart1->Checked=true;
Table1->Checked=false;
}
此方法是主窗体的菜单项的OnClick处理句柄,猜的没错,这是在显示TChartForm子窗体。首先检查ActiveChild变量是否非0,如果有激活动子窗体ActiveChild将非0。如果ActiveChild不为0,删除此变量关联的指针以摧毁活动子窗体,否则程序会将子窗体一个接一个地堆叠在一起。接着创建一个TChartForm类的实例,将new操作返回到指针赋予ActiveChild变量,这样ActiveChild总是包含一个指向当前子窗体的指针。最后调用Sow()方法显示子窗体。最后两行代码确保代表表单或图形显示的菜单项显示一个选中标记。为完成ActiveChild变量的讨论,我得带你回到子窗体单元一会儿。每个子窗体都含有一个如下的OnClose事件的事件句柄:
void __fastcall TChartForm::FormClose(Tobject *Sender,
TCloseAction &Action)
{
MainForm->ActiveChild=0;
MainForm->Chart1->Checked=false;
Action=caFree;
}
注意当窗体被摧毁时,主窗体的ActiveChild被置为0,并将与子窗体关联的菜单项置为未选中。Action参数置为caFree,以通知VCL释放与此窗体关联的内存。你或许会疑惑为何FormClose句柄包含上面最后两行。答案是每个子窗体都有一个Close按钮用来关闭窗体,如果用Close按钮来关闭窗体,就需要释放内存和uncheck菜单项。
额外特征
例子程序至少还有一个尚未讨论的特征,就是如果子窗体比主窗体大,要重新调整主窗体大小以容纳子窗体。这些语句放在子窗体的CreateParams()方法中。之前我展示过一个简单的CreateParams()例子,但没有放进调整主窗体大小的语句。列表B中有完整的CreateParams()方法,和先前展示唯一不同的是包含以下语句:
if(Width>MainForm->ClientWidth)
MainForm->ClientWidth=Width;
if(Height>(MainForm->StatusBar->Top-MainForm->ToolBar->Height))
MainForm->ClientHeight=Height+
MainForm->ToolBar->Height+
MainForm->StatusBar->Height ;
这几条语句检查子窗体的宽度是否大于主窗体的ClientWidth属性,如果是,主窗体的ClientWidth置为子窗体的宽度。余下的几行作的是同样的事情,只不过针对的是主窗体的客户区高度而已。这些语句的结果是主窗体总是被调整到能完全容纳被显示的子窗体。范例程序还考虑了主窗体调整大小时的情况。如果主窗口大小有变化,子窗体大小也必须变化以进行充满主窗体的客户区。以下语句演示了主窗体的OnResize事件句柄:
void __fastcall TMainForm::FormResize(Tobject *Sender)
{
if(ActiveChild)
{
ActiveChild->Width=ClientRect.Right;
ActiveChild->Height=(MainForm->StatusBar->Top-1)-
ActiveChild->Top;
}
}
这些语句相当直接,无需我逐条解释。注意首先检查ActiveChild变量确保非0(即指向某子窗体),很明显如果当前没有激活任何子窗体,在OnResize中就什么都不用干。其余语句是CreateParams()中看到语句的变种,只是简单地计算子窗体的新尺寸并设置相应的Width和Height属性。结语
列表A包含了例子程序主窗体的代码。列表B示出了TChartForm单元的源码。头文件都没有给出因为没有什么有意义的语句,也未给出TTableForm单元的语句,因为与ChatForm单元类似。你可以在例子程序。将子窗体“寄居”于主窗体提供了一种清晰的替代MDI的方法,对那些只能以无模式窗体形式向用户显示数据的程序也是一种替代,使用子窗体允许你使用窗体设计器设计你的从窗口,并将操纵子窗体的代码放在一个地方。
列表A:MAINU.CPP
#include
#pragma hdrstop
#include \"MainU.h\"
#include \"ChartU.h\"
#include \"TableU.h\"
#pragma resource \"*.dfm\"
TMainForm *MainForm;
__fastcall TMainForm::TMainForm(Tcomponent* Owner)
: Tform(Owner)
{
//清0以防包含随机数
ActiveChild=0;
//打开数据表
Table->Active=true;
}
void __fastcall TMainForm::Table1Click(Tobject *Sender)
{
if(Table1->Checked) return;
if(ActiveChild){
delete ActiveChild;
ActiveChild=0;
}
TTableForm *form=new TTableForm(this);
//将DBGrid的DBGrid::DataSource属性赋给数据源
form->DBGrid->DataSource=DataSource;
//跟踪活动子窗体
Active=form;
form->Show();
Table1->Checked=true;
Chart1->Checked=false;
}
void __fastcall TMainForm::Chart1Click(Tobject *Sender)
{
if(Chart1->Checked) return;
if(ActiveChild){
delete ActiveChild;
ActiveChild=0;
}
TChartForm *form=new TChartForm(this);
Active=form;
form->Show();
Chart1->Checked=true;
Table1->Checked=false;
}
void __fastcall TMainForm::FormResize(Tobject *Sender)
{
if(ActiveChild){
ActiveChild->Width=ClientRect.Right;
ActiveChild->Height=(MainForm->StatusBar->Top-1)-
ActiveChild->Top;
}
}
列表B:CHARTU.CPP
#include
#pragma hdrstop
#include \"ChartU.h\"
#include \"MainU.h\"
#pragma resource \"*.dfm\"
TChartForm *ChartForm;
__fastcall TChartForm::TChartForm(Tcomponent* Owner)
: Tform(Owner)
{
}
void __fastcall TChartForm::CreateParams(TCreateParams& Params)
{
//调用基类CreateParams方法
Tform::CreateParams(Params);
//子窗口类型
Params.Style=WS_CHILD|WS_CLIPSIBLINGS;
//设置父为主窗体
Params.WndParent=MainForm->Handle;
Params.X=0;
if(Width>MainForm->ClientWidth)
MainForm->ClientWidth=Width;
if(Height>(MainForm->StatusBar->Top-MainForm->ToolBar->Height))
MainForm->ClientHeight=Height+
MainForm->ToolBar->Height+
MainForm->StatusBar->Height;
Params.Y=MainForm->ToolBar->Height+1;
Params.Width=MainForm->ClientRect.Right;
Params.Height=(MainForm->StatusBar->Top-1)-Params.Y;
}
void __fastcall TChartForm::FormClose(Tobject *Sender,
TCloseAction &Action)
{
MainForm->ActiveChild=0;
MainForm->Chart1->Checked=false;
Action=caFree;
}
void __fastcall TChartForm::CloseBtnClick(Tobject *Sender)
{
Close();
}