动态创建单文档界面的控制类 通过窗体菜单及单文档界面的各种控件，可完成应用程序与用户之间的交互操作。使用Visual C++程序设计方法创建单文档界面时，以动态方式创建窗体控件，对控件的交互操作应由指定的消息处理程序完成其功能。本文通过MyCal计算器应用程序动态创建窗体的编辑控件、按钮控件、成组控件及列表框控件，说明如何为动态创建的命令按钮控件及圆形按钮控件设置消息处理程序，以完成用户指定的不同基数制的求和运算，应用程序窗体如图所示。 动态创建可视化控件 由于单文档界面无法直接由生成器创建可视化控件，必须通过构造的控制类动态创建单文档界面中的所有控件。
1．创建按钮控件
类CButton被用来构造命令按钮控件、圆形按钮控件、检查框控件和成组控件。通过CButton类构造上述控件时，将Create成员函数中的控制文本参数所包含的控件风格定义为不同数值，就可根据需要创建上述按钮类中任何一种可视化控件。在此说明本文对命令按钮控件、圆形按钮控件、成组控件的风格设置:
风格设置　　　　　　　　　 风格说明
BS_PUSHBUTTON　　　　　　 命令按钮控件
BS_AUTORADIOBUTTON　　　　圆形按钮控件
BS_GROUPBOX　　　　　　　 成组控件
·创建圆形按钮控件
由类CButton创建自己的CRadioButton圆形按钮派生类，在Create成员函数的控制文本参数中定义圆形按钮风格：
class CRadioButton:public CButton
{
public:
BOOL Create(const char FAR* lpCaption,
const RECT& rect,
CWnd* pParentWnd,UINT nID){
return CButton::Create(lpCaption,
//圆形按钮的显示文本
WS_CHILD|WS_VISIBLE|WS_TABSTOP|
BS_AUTORADIOBUTTON,
//圆形按钮的控制文本
rect, //控件尺寸
pParentWnd, //父窗口
nID);} //圆形按钮控件标识符
};
·创建命令按钮控件
类CButton创建CxButton命令按钮派生类，Create成员函数中包含风格设置的控制文本参数应定义为：WS_CHILD|WS_VISIBLE|WS_TABSTOP| BS_PUSH-BUTTON。构造命令按钮类及Create成员函数时，只需变换圆形按钮类中的派生类名称，并将含有命令按钮风格的控制文本加至Create成员函数中。
·创建成组控件
类CButton创建CGroupBox成组控件派生类，将Create成员函数中包含成组控件风格的控制文本参数指定为:WS_CHILD|WS_VISIBLE|WS_TABSTOP| BS_GR-OUPBOX。创建成组控件派生类及Create成员函数时，只需修改构造圆形按钮类的派生类名称，同时将已定义为成组控件风格的控制文本添加到Create成员函数中。
2．创建列表框控件
类CListBox用来构造单选或多选列表框控件，Create成员函数定义如下：
BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,UINT nID);
3．创建编辑框控件
类CEdit可构造单行或多行的编辑框控件，Create成员函数说明如下：
BOOL Create(DWORD dwStyle,const RECT& rect,CWnd* pParentWnd,UINT nID);

动态创建单文档界面的计算器控件

通过AppWizad(.exe)创建一个单文档的MyCal应用程序窗体框架，由于CView文档/视类结构中提供了文档显示和用户操作功能，必须在创建CView的 CMyCalView派生类的MyCalView.h模块中构造圆形按钮、命令按钮、成组控件的CRadioButton、CxButton 、CGroupBox派生类及Create成员函数，其命令格式如综上所述。
1．创建窗体中的计算器控件
·指定可视化控件的控制指针
为了动态创建窗体中的计算器控件，在MyCalView.h模块CMyCalView派生类的protected语句中，对每个可视化控件定义一个控制指针，各控制指针说明如下：
protected:
CEdit* pOperand1Box;
//加数编辑框的控制指针
CEdit* pOperand2Box;
//被加树编辑框的控制指针
CEdit* pResultBox;
//和的编辑框的控制指针
CGroupBox* pRadixGrp;
//基数制设置的成组控件的控制指针
CRadioButton* pDecimalRbt;
//"十进制"圆形按钮的控制指针
CRadioButton* pHexRbt;
//"十六进制"圆形按钮的控制指针
CRadioButton* pBinaryRbt;
//"二进制"圆形按钮的控制指针
CxButton* pClearBtn;
//清除命令按钮的控制指针
CxButton* pCalcBtn;
//求和命令按钮的控制指针
CxButton* pStoreBtn;
//存储命令按钮的控制指针
CListBox* pVariList;
//存储和的列表框控制指针
·动态创建可视化控件
由于CView类提供文档显示功能，应用程序将在其派生类CMyCalView的OnCreate消息处理程序中动态创建计算器的所有控制类。由于动态创建可视化控件时必须指定控件尺寸，为此在MyCalView.h模块的CMyCalView派生类中还需指定一个自定义函数makerect，其程序代码如下所示：
void makerect(int X,int Y,int W,int H,CRect& r)
{ r.SetRect(X,Y,X+W,Y+H);}
通过View菜单ClassWized选项的Message Maps页面，选择CMyCalView派生类，在Message列表框中选定WM_CREATE消息，MyCalView.h模块添加消息映射，同时MyCalView.cpp模块加入OnCreate的消息处理程序入口，并通过OnCreate消息处理程序构造所需的各种控制类，在此对同一控制类仅给出一个可视化控件的动态创建方法，OnCreate消息处理程序中添加的程序代码显示如下：
//TODO: Add your specialized creation code here
char s[81],c Vari[81];
int k,j;
CRect r;
DWORD dwBoxStyle=WS_CHILD|WS_VISIBLE-|WS_BORDER|ES_LEFT|
ES_AUTOHSCROLL|ES_UPPERCASE;
//设置编辑框控件风格
DWORD dwListBoxStyle=WS_CHILD|WS_VISIBLE-|WS_VSCROLL|
LBS_STANDARD; //设置列表框控件风格
makerect(20,20,90,20,r);
pOperand1Box=new CEdit();
//动态创建加数编辑框控件
pOperand1Box->Create(dwBoxStyle,r,this,-ID_OPERAND1_EDIT);
pOperand1Box->LimitText();
makerect(120,21,18,18,r);
pOperantorTxt=new CStatic();
//动态创建"+"号的静态文本控件
pOperantorTxt->Create(" +",dwStaticStyle,-r,this,-1);
makerect(20,80,120,102,r);
pVariList=new CListBox();
//动态创建存储和的列表框控件
//没有加到加速键表的控件标识符，应由define宏将其定义于CMyCalView.h模块中
pVariList->Create(dwListBoxStyle,r,this,-ID_VARIABLE_LST);
//在所创建的列表框中添加A~Z的存储序号
j=0;
for(c='A';c<='Z';c++){
sprintf(s,"%c:",c);
pVariList->AddString(s);
Vari[j]=c;
j++;}
makerect(160,58,120,123,r);
pRadixGrp=new CGroupBox(); //动态创建放置圆形按钮控件的基数制成组控件
pRadixGrp->Create("Radix",r,this,ID_RA-DIX_GRP);
makerect(176,90,90,15,r);
pDecimalRbt=new CRadioButton();
//动态创建"十进制"的圆形按钮控件
pDecimalRbt->Create("&Decimal",r,this,-ID_DECIMAL_RBT);
makerect(305,75,80,20,r);
pCalcBtn=new CxButton();
//动态创建求和命令按钮控件
pCalcBtn->Create("&Calc",r,this,ID_-CALC_BTN,TRUE);
k=0; //列表框中的序号计数器
对于窗体中同一控制类的其它可视化控件，需定义不同的控件尺寸、控件显示文本及控件标识符，再按同样方式进行创建。

定义单击命令按钮及圆形按钮的消息处理程序

本文所示计算器，可完成十进制、十六进制、二进制数的求和计算，同时根据需要将计算结果按顺序存入Variables列表框，或将加数、被加数及和的编辑框清零。
1．加速键表中添加命令按钮及圆型按钮标识符
由于窗体中动态创建了命令按钮及圆型按钮，要在MyCalView.h模块CMyCalView派生类中指定命令按钮及圆形按钮的消息处理程序，首先将Calc（求和）、Store（存储）、Clear（清除）命令按钮及Decimal（十进制）、Hexadecimal（十六进制）、Binary（二进制）圆形按钮标识符添加到资源文件Accelerator部分的IDR_MIANFRAME加速键表中，标识符及快捷键定义如下所示：
标识符　　　　　　快捷键定义　　说明
ID_DECIMAL_RBT　　Alt+D　　　　十进制圆形按钮
ID_HEX_RBT　　　　Alt+H　　　　十六进制圆形按钮
ID_BINARY_RBT　　 Alt+B　　　　二进制圆形按钮
ID_CALC_BTN　　 　Alt+C　　　　求和命令按钮
ID_STORE_BTN　　　Alt+S　　　　存储命令按钮
ID_CLEAR_BTN　　　Alt+R　　　　清除命令按钮

2．生成单击命令按钮及圆型按钮的消息处理程序
通过View菜单中的ClassWized选项，在Message Maps页面中选择CMyCalView派生类，分别选出Object IDs列表框中的求和、清除及存储命令按钮和十进制、十六进制、二进制圆形按钮标识符，在Message列表框中为上述每个控件选择Command消息，通过Add Member Function对话框定义消息处理程序名称，MyCalView.h模块将创建上述命令按钮及圆形按钮的消息映射，同时在MyCalView.cpp模块中加入与此对应的消息处理程序入口。
3．消息处理程序中添加程序代码
由于MyCalView.cpp模块仅给出单击命令按钮及圆形按钮的消息处理程序入口，要完成各种操作过程必须人为添加相关的程序代码，在此仅列出单击十六进制圆形按钮、单击求和及存储命令按钮的消息处理程序。单击窗体中Hexadecimal圆形按钮，设置十六进制基数制，再单击Calc命令按钮，完成两个十六进制数的求和运算。为了方便十六进制数的转换，在MyCalView.h模块的CMyCalView派生类中定义一个如下所示的自定义函数：
void setHexaDecimal(CEdit* pEdit)
{
char s[81],*ss;
int nRadix,MaxStringLen;
long n;
MaxStringLen=80;
pEdit->GetWindowText(s,MaxStringLen);
n=strtol(s,&ss,nRadix);
_ltoa(n,s,16);
pEdit->SetWindowText(s);
}
MyCalView.cpp模块中单击Hexadecimal圆形按钮的消息处理程序如下所示：
void CMycalView::OnHexRbt()
{
//TODO: Add your command handler code here
int nRadix;
setHexaDecimal(pOperand1Box);
setHexaDecimal(pOperand2Box);
setHexaDecimal(pResultBox);
nRadix=16;
}
MyCalView.cpp模块中单击Calc命令按钮的消息处理程序为：
void CMycalView::OnCalcBtn()
{
//TODO: Add your command handler code here
long x,y,z;
char s[81],*ss;
int MaxStringLen;
MaxStringLen=80;
pOperand1Box->GetWindowText(s,MaxStringLen);
x=strtol(s,&ss,nRadix);
pOperand2Box->GetWindowText(s,MaxStringLen);
y=strtol(s,&ss,nRadix);
z=x+y;
_ltoa(z,s,nRadix);
pResultBox->SetWindowText(s);
}
单击Store命令按钮，将计算结果顺序存入Variables列表框,MyCalView.cpp模块中Store命令按钮的消息处理程序为：
void CMycalView::OnStoreBtn()
{
// TODO: Add your command handler code here
int MaxStringLen,k;
char s1[81],formatApptStr[81],*ss, Vari[81],s[81];
MaxStringLen=80;
pResultBox->GetWindowText(s1,Max-StringLen);
sprintf(s,"%c:",Vari[k]);
pVariList->DeleteString(k);
sprintf(formatApptStr,"%2s %s",s,s1);
pVariList->AddString(formatApptStr);
k++;
}
由此可见，通过构造控制类可在单文档界面中动态创建各种控件，由资源文件中控件标识符生成消息处理程序入口，在相应处理程序中添加特定功能的程序代码，就可为动态创建的可视化控件制作出完整的消息处理程序。
(廖 琪、廖 彤)