第五章 增加对话框
完整有特色的交互式应用程序可能拥有许多不同的窗口对象(如窗口、控件、对话框)。主窗口之外的所有窗口都称为子窗口,每个子窗口都只有一个父窗口,一个父窗口可以有多个子窗口。
这种父子关系形成了各个应用程序的相关父子窗口系统。在这个系统中,主窗口是终极父窗口。
有两种子窗口:一个是独立的子窗口,这种子窗口能控制其自身的显示与定位。消息框和对话框都是独立的子窗口。另一类是非独立的子窗口,这种子窗口在其父窗口的表面显示,而且只能在父窗口的范围之内移动。控件(如消息框中的按钮)就是非独立子窗口。这一章将讲述独立的子窗口。
5.1 增加一个对话框
对话框很象一个弹出式窗口,但它通常在屏幕上停留一段时间且执行一种特定的任务。对话框的表面一般都有很多控件组合来显示静态文本、完成数据输入、列表内容选择、互锁按钮选择能内容并根据用户的选择和输入执行某种任务或在激活另一个对话框。
象弹出窗口一样,对话框是一个独立的子窗口。从概念上讲,增加一个对话框与增加一个弹出式窗口别无二样。虽然对话框酷似窗口,但它与窗口还存在着重要差异:
l 对话框类是由TDialog派生的,而不是从TWindow派生的。不过TDialog和TWindow两个都是从TObject派生的。
l 通常,对话框需要用户规定其大小、位置。
l 通常,对话框执行一项较短的任务且返回一个值
例如:CanClose消息框根据用户的选择返回一个1或者0的应答。
5.2 增加用户自定义对话框的数据成员与操作函数
为完成用户特定的对话框界面元素时,需要自己在布局上、控件选择上重新定义。Object UNIX Class Library提供了十三个控件类可供选择,这些类都从TControl类派生出来的,而Tcontrol类又是从TObject基类派生的。用户可以参考后面的详细类参考选择自己实际需要的控件类设计自己的对话框对象。下面是一个对话框对象的范例,您可以模仿该例子构造自己的对话框对象:
class TUserDialog : public TDialog {
public:
TEdit *Edit1;
TComboBox *ComboBox1;
TLabel *Label1;
public:
virtual void InitDialog(void);
virtual int PressEnterEvent(void);
TUserDialog(char *caption,int left,int top,int width,
int height,int ftcolor,int bkcolor);
};
5.2.1 增加对象成员(控件)到对话框中
正如上面例子所定义的描述,用户在对话框中定义了三个对象属性:输入条Edit1、标签(静态文本)Label1以及下拉列表框ComboBox1。这三个对象各从TEdit类、TLabel类、TComboBox类派生。一般为对对话框的按钮进行分类,对话框还增加了线属性以及按钮属性。
在定义好数据成员后,您应该在对话框类的成员虚拟函数InitDialog中对您所定义的对象属性进行实例化,以确定各个对象的实际位置以及所表现的属性如颜色、状态、标题等内容。每个控件都有其属性,比如,您可以设置某个对话框的键盘响应属性。假设您不允许用户在输入条上输入字符,您可以这样设置:Edit1->KeyEvent=FALSE,其它的属性请参考后面类参考。
如果您想修改某个控件,您可以在设置完它的属性后重新显示它。比如您想修改标签的显示文本,您可以这样设置:
Label1->Caption=”其它文本”;
Label1->Show();
如果读者在仔细分析程序是,您可以发现一个函数InsertControl,该函数把用户定义好的控件追加到对话框的控件列表中,这样便于Object UNIX Class Library对每个控件进行定位以及判断各个控件的按键事件。
void TUserDialog::InitDialog(void)
{
Label1= new TLabel("单位全称:",4,1,BLACK_WHITE);
TDialog::InsertControl((TControl *)Label1);
Edit1=new TEdit(50,0,13,1,52,1,BLACK_WHITE,WHITE_WHITE);
TDialog::InsertControl((TControl *)Edit1);
ComboBox1=new TComboBox("帐户种类",13,6,10,4,BLACK_WHITE,
BLACK_CYAN,CYAN_CYAN,WHITE_BLUE,BLUE_BLUE);
ComboBox1->AddString("基本帐户");
ComboBox1->AddString("一般帐户");
ComboBox1->AddString("专用帐户");
ComboBox1->AddString("临时帐户");
TDialog::InsertControl((TControl *)ComboBox1);
TDialog::InsertControl((TControl *)new TLine(M_HORZ,
0,13,70,17,BLACK_WHITE));
TDialog::InsertControl((TControl *)new TButton(SAVE_BUTTON,
"确认",4,14,BLACK_WHITE,WHITE_MAGENTA));
TDialog::InsertControl((TControl *)new TButton(EXIT_BUTTON,
"退出",46,14,BLACK_WHITE,WHITE_MAGENTA));
}
5.2.2 响应对话框事件
一般对话框都为完成某项任务而设置,Object UNIX Class Library提供了您对所有控件按下回车键后的事件响应。比如在输入条输入字符串后,需要根据输入的内容查找数据库,然后显示在对话框的某个静态文本区域,则您需要得到对输入条的按键事件。Object UNIX Class Library基类提供了虚函数PressEnterEvent,用户需要重载该函数,以便针对不同的业务来完成不同的事件响应。
下面是一个基本的范例:
int TUserDialog:

{
TButton *Button;
if(strcmp(ControlList->Control->GetClassName(),"BUTTON")==0){
Button=(TButton *)ControlList->Control;
switch(Button->ButtonType) {
case SAVE_BUTTON:
//处理按下确认键,该段程序需要用户自己编写
break;
case EXIT_BUTTON:
//处理按下确认键,该段程序需要用户自己编写
break;
}
}
return 1;
}
从上述程序可以看出,由于对话框维护着一个该对话框内的控件列表,所以用户可以取得所有对话框内控件的所有事件。用户可以通过TDialog类的数据成员ControlList来取得当前的控件指针。ControlList是一个控件的双向列表,通过引用其数据成员Control可以得到当前的控件指针。通过GetClassName函数知道该控件是何种类型的控件来进行进一步的判断以进行某项控件的事件。
由于所有的控件都采用指向基类TObject的指针,通过类型转换,取得正确的某项控件的指针来进行必要的业务处理。
上述例子是一个事件处理的框架,用户可以模仿它处理自己的事件。
5.2.3 定制自己的对话框初始化
TDialog类提供一个虚函数ExecDialog,以便在对话框显示时,根据用户的特殊需要来设置对话框显示的初始状态。
比如,用户想在对话框显示时对输入条进行赋初值,您可以重载ExecDialog函数,方法如下:
int TUserDialog::ExecDialog(void)
{
strcpy(Edit1->Text,”1234567890”);
return TDialog::ExecDialog();
}
5.3 运行对话框
在对话框都定义好后,应该在主窗口的初始化函数中实例化每个对话框,这样就没有必要在每次运行它之前实例化它,当然,您可以在运行时才实例化它。
假设您准备在主窗口中实例化对话框,则采用如下方法:
TLfrWindow(char *caption,int left,int top,int width,int height,int ftcolor,int bkcolor) : TWindow(caption,left,top,width,height,ftcolor,bkcolor)
{
UserDialog=new TUserDialog("对话框",5,5,70,16,BLACK_WHITE,
WHITE_WHITE);
}
当然,您应该在主窗口的类中定义一个对话框的类对象UserDialog。
为了在主窗口菜单选择项中执行某个对话框,您可以采用TDialog类的成员函数ExecDialog。这里修改上面一章的例子,在按下打开文件菜单项是执行对话框:
void TLfrWindow::OpenFile(void)
{
UserDialog->ExecDialog();
}
当按下对话框的退出按钮后,对话框消失,但它还在内存中保留着,您下次还可以继续通过ExecDialog打开他,除非您执行如下指令:delete UserDialog,则对话框将从内存中撤除,下次执行它时,需要生成一个新的对话框对象。
5.4 控件对象
控件是构成窗口或对话框的用户界面的部分或全部的直观设备。例如,文件对话框的OK和Cancel按钮都是控件。
Object UNIX Class Library提供有多种控件类型,包括列表框、下拉列表框、编辑条、按钮、组合框、校验键、互锁键、文本文件显示、数据库Browser、静态标签文本等。
Object UNIX Class Library的TControl类提供了所有控件共享的属性。它的派生类定义了各种控件的特有属性。例如,TEdit和TList定义编辑控制和列表控制所特有的属性,还应注意到,TControl是从TObject中派生的。
5.4.1 建立对话框控件
虽然控件和对话框的表现形式是等同的,但在它们之间存在着重要的编程差异。
但是,控件大多数是由Object UNIX Class Library的对象表示的。父窗口对话框对其控件的管理通过Object UNIX Class Library对象定义的一组成员函数进行的。例如,为获得用户从列表框中选择的文本项,就需要调用列表框控件对象的成员函数GetSelString()或者通过数据成员CurList->Text得到。与对话框对象一样,控件也有对应的直观成份。作为子窗口对象的控件,其对象都有其父窗口对话框的Parent属性,并引用其父窗口对话框的相对坐标位置,并通过父窗口对话框的对象数据属性ControlList来引用某个对象的指针。当然,有些对象也有其自己的唯一标识。例如按钮控件,父窗口对话框空控件ID来标识正在执行的控件,如当用户触发一个按钮时便需要按钮标识。为清晰起见,应该为每个控件ID定义常量:
#define OK_BUTTON 1
#define CACEL_BUTTON 2
#define PRINT_BUTTON 3
等等,该定义可以在define.hpp头文件中找到。
5.4.2 作为数据成员的控件对象
有时,把指向控件对象的指针作为窗口对象的一个数据成员存储会带来一些方便,这只是对那些后续要通过直接调用其对象函数来处理的子窗口是必须的。在这种情况下,用户将每个控件对象存放在各别的数据成员中。下面是TUserDialog对象定义的一部分:
class TUserDialog : public TDialog {
public:
TEdit *Edit1;
TList *List1;
…
};
一旦建立了这些控件对象之后,便可以借助成员函数调用来处理她们。例如,调用List1->AddString可以向列表框List1中增加一个串。
5.4.3 管理控件对象
任何带有控件对象的对话框类都必须定义用来构造控件对象的初始化InitDialog函数。在初始化函数中建立控件对象。
下面是该初始化函数的实例:
void TUserDialog::InitDialog(void)
{
Label1= new TLabel("单位全称:",4,1,BLACK_WHITE);
TDialog::InsertControl((TControl *)Label1);
Edit1=new TEdit(50,0,13,1,52,1,BLACK_WHITE,WHITE_WHITE);
TDialog::InsertControl((TControl *)Edit1);
…
}
由于对话框类TDialog中的成员函数InsertControl维护着控件的列表,所以在以后的对象引用中可以采用数据成员ControlList来引用各个控件对象。该成员数据是一个控件对象的双向列表,通过Next和Prev指针移动可以得到上一个控件和下一个控件。
详细说明请参阅后面的类说明。
5.4.4 对控件对象事件的响应
在前面已经看到,对菜单事件的响应是通过定义消息响应函数来实现的。这里对控件事件的响应采用对虚函数PressEnterEvent的重载来响应控件时间。
int TUserDialog:

{
TButton *Button;
if(strcmp(ControlList->Control->GetClassName(),"BUTTON")==0){
Button=(TButton *)ControlList->Control;
switch(Button->ButtonType) {
case SAVE_BUTTON:
//处理按下确认键,该段程序需要用户自己编写
break;
case EXIT_BUTTON:
//处理按下确认键,该段程序需要用户自己编写
break;
}
}
return 1;
}
用户通过类成员函数GetClassName来比较不同的控件以决定响应哪一个控件的事件。
对按钮事件的响应有别于其它控件,因为按钮控件有其唯一的ID标识,所以采用case语句比较用户按下哪个按钮控件。
延伸阅读
文章来源于领测软件测试网 https://www.ltesting.net/