将窗体从属于主窗体
当前位置:以往代写 > C/C++ 教程 >将窗体从属于主窗体
2019-06-13

将窗体从属于主窗体

将窗体从属于主窗体

副标题#e#

险些所有正式一点的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是尺度版则没有数据库元件)你可以通过点击菜单项或东西按钮来选择显示表单照旧图形窗体,在你作出选择时,勾当窗体被摧毁而被选窗体被显示,子窗体在主窗体的东西条下方、状态条上方的客户区显示,并且随主窗体巨细变换而随时保持布满客户区。


#p#副标题#e#

重载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属性。鉴于指定父工具属性相对直接明白,我不在这个主题上深入更多。

#p#副标题#e#

配置子窗体的属性

除了CreateParams()要领中的代码外,还得配置一些子窗体的属性,大都属性可以保存缺省值,但AutoScroll属性应设为false,虽然,前提是你的窗体要设计为不必卷动的窗体气势气魄。因为子窗口的巨细和位置在CreateParams()中设定,所以Position属性可置为poDefault。Caption和BorderIcon属性将被忽略,故而无需指定。确保BorderStyle置为bsSizeable,尚有BorderWidth置为0,假如此二属性设成其它值,子窗体与主窗体会不协调。

窗体的其它元件

#p#分页标题#e#

许多时候,除了从属窗体外,主窗体还包括此外元件,好比东西条和状态条,此时配置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是公有的,因为子窗体要会见这个变量。我顿时会演示如何利用这一变量。此刻来书写显示子窗体的代码,先看下面措施行,然后我来表明。

#p#副标题#e#

void __fastcall TMainForm::Chart1Click(Tobject *Sender)
{
if(ActiveChild)
delete ActiveChild;
TChartForm * form=new TChartForm(this);
ActiveChild=form;
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()要领,和先前展示独一差异的是包括以下语句:

#p#副标题#e#

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属性。

结语

#p#分页标题#e#

列表A包括了例子措施主窗体的代码。列表B示出了TChartForm单位的源码。头文件都没有给出因为没有什么有意义的语句,也未给出TTableForm单位的语句,因为与ChatForm单位雷同。你可以在www.reisdorph.com下载例子措施。将子窗体“借居”于主窗体提供了一种清晰的替代MDI的要领,对那些只能以无模式窗体形式向用户显示数据的措施也是一种替代,利用子窗体答允你利用窗体设计器设计你的从窗口,并将哄骗子窗体的代码放在一个处所。

#p#副标题#e#

列表A:MAINU.CPP

#include <vcl.h>
#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 <vcl.h>
#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();
}

    关键字:

在线提交作业