当前位置导航:炫浪网>>网络学院>>编程开发>>C++教程>>C++基础入门教程

将窗体从属于主窗体

几乎所有正式一点的C++ Builder程序除了主窗体外都还有从属窗体,有时是对话框,有时是无模式窗口。VCL使得创建和显示从属窗体都易如反掌。但不是所有程序都适于采用无模式窗体,有些程序需要在一个主窗体内显示不同的内容。本文讨论如何将一个从属窗体“寄居”于主窗体中,从属窗体看上去是主窗体的一部分,用户甚至不知道一个从窗体正被显示。图A显示了一个主窗体,其客户区是一个从窗体。

理解子/父联系
  这类程序的基本思路是让所有从属窗体都作主窗体的子窗体,这种设计在其他框架(如OWL或MFC)中很常见,但在VCL程序中却不常见。VCL不允许简单地指定一下属性就使一个窗体从属于另一窗体,要做到这一点还得付出点小小的劳动。你得告诉Microsoft Windows从属窗体是主窗体的子对象,在C++ Builder编程中一般趋于认为窗体是窗口,元件是子对象,实际上从Windows的观点来看,窗体和元件都是窗口。可以将任一窗口
(窗体和元件)指定为另一窗口的子对象,只要你暂时跳出VCL圈子。

更好的“鼠夹”
  将一个窗体附属于一个主窗体的一个好处是你可以象设计任何其他从属窗体一样设计子窗体,就是说你创建一个新的窗体,在其上添加元件并书写这个窗体的代码。这样使得设计你的子窗体变得容易,并将所有操纵子窗体的代码集中在一个地方。

程序设计范例
  先给出一些程序的背景,程序名叫PARENTING,有一个主窗体,主窗体的顶部和底部各有一个工具条(Tool Bar)和状态条(Status bar),除主窗体外,还有两个子窗体,一个叫TTableForm,用栅格显示ANIMAL.DBF数据表,ANIMAL表是C++ Builder带的数据库样本的一个表。另一个子窗体TChartForm用Tchart显示ANIMAL表。(如果你购买的C++ Builder是标准版则没有数据库元件)你可以通过点击菜单项或工具按钮来选择显示表单还是图形窗体,在你作出选择时,活动窗体被摧毁而被选窗体被显示,子窗体在主窗体的工具条下方、状态条上方的客户区显示,而且随主窗体大小变动而随时保持充满客户区。

重载CreateParams()
  如前所述,为让主窗体控制从属窗体,需要将主窗体设为从窗体的“父”,这可以通过重载CreateParams()方法来完成。CreateParams()在VCL创建与窗体联系的窗口时调用,CreateParams()的声明如下:
void __fastcall CreateParams(TCreateParams& Params);
CreateParams()的唯一参数是对一个TCreateParams结构体的引用。在VCL中TCreateParams定义如下:


struct TCreateParams
{
char *Caption;
int Style;
int ExStyle;
int X;
int Y;
int Width;
int Height;
HWND WndParent;
void *Param;
tagWNDCLASSA WindowClass;
char WinClassName[64];
};


  此结构包含了Windows创建一个窗口所需的所有信息(如果你曾用API进行Windows编程,你一定能意识到TCreateParams的成员对Windows CREATESTRUCT结构的映射)。在重载CreateParams()时,首先调用基类的CreateParams()方法,然后修改TCreateParams结构的个别成员变量。一个重载过的CreateParams()方法看起来大致如下:


void __fastcall TChartForm::CreateParams(TCreateParams& Params)
{
Tform::CreateParams(Params);
Params.Style=WS_CHILD|WS_CLIPSIBLINGS;
Params.WndParent=MainForm->Handle;
Params.X=0;
Params.Y=0;
Params.Width=MainForm->ClientRect.Right;
Params.Height=MainForm->ClientRect.Bottom;
}


  程序的关键是设置TCreateParams结构体的Style和WndParent成员,Style设WS_CHILD 和WS_CLIPSIBLINGS窗口式样,WS_CHILD指定窗口为另一窗口的子窗口。根据定义,一个子窗口是没有标题棒的,设计时的标题棒在Windows在运行时创建窗体会被去掉。WS_CLIPSIBLINGS保证主窗口的不同子窗口在窗体绘制时不互相干涉。很明显,一个子窗口必须得有一个父对象,通过将父窗口句柄指定给TCreateParams结构体WndParent 成员就指定了父对象,正如前面代码所示,WndParent成员设置为主窗体的Handle属性。鉴于指定父对象属性相对直接明了,我不在这个主题上深入更多。

设置子窗体的属性
  除了CreateParams()方法中的代码外,还得设置一些子窗体的属性,多数属性可以保留缺省值,但AutoScroll属性应设为false,当然,前提是你的窗体要设计为不必卷动的窗体风格。因为子窗口的大小和位置在CreateParams()中设定,所以Position属性可置为poDefault。Caption和BorderIcon属性将被忽略,故而无需指定。确保BorderStyle置为bsSizeable,还有BorderWidth置为0,如果此二属性设成其它值,子窗体与主窗体会不协调。

窗体的其它元件
  很多时候,除了从属窗体外,主窗体还包含别的元件,比如工具条和状态条,此时设置TCreateParams结构体的X、Y、Width和Height成员时得考虑到工具条和状态条,子窗体应与顶部的工具条和底部队状态条协调。因此设置TCreateParams结构体的成员的代码应该是:


Params.X=0;
Params.Y=MainForm->ToolBar->Height+1;
Params.Width=MainForm->ClientRect.Right;
Params.Height=(MainForm->StatusBar->Top-1)-Params.Y;


  注意Y设为工具条底部加1,子窗体宽度置为主窗体客户区宽度,高度根据子窗体和状态条的顶部计算,基本上为界于工具条底部和状态条底部之间的主窗体客户区。这些就是使从属窗体“寄居”于主窗体的所有要求,你可能还有其它想在子窗体中实现的特征,我将把这些特征的讨论留到后面。

设置主窗体
  主窗体也得进行设置以控制其“收留”的子窗体。首先需要将子窗体从自动创建窗体列表中去掉,需要时再创建它们。如果不从列表中去掉,则当你的应用程序启动时它们会自动显示。你还需要一个变量来跟踪当前的活动子窗体,在主窗体的Public区声明如下变量,Tform * ActiveChild; ActiveChild是公有的,因为子窗体要访问这个变量。我马上会演示如何使用这一变量。现在来书写显示子窗体的代码,先看下面程序行,然后我来解释。


void __fastcall TMainForm::Chart1Click(Tobject *Sender)
{
if(ActiveChild)
delete ActiveChild;

TChartForm * form=new TChartForm(this);
ActiveChild=form;

共3页 首页 上一页 1 2 3 下一页 尾页 跳转到
相关内容
赞助商链接