第九篇:模式对话框和通用控件(上)
对话框是一个真正的窗口,它不但可以接受消息,而且可以被移动和关闭,还可以在它的客户区中进行绘图操作。对话框可以分为模式对话框和无模式对话框两种,两者区别是在对话框被关闭之前用户能否在同一应用程序的其他地方进行工作。举例说明:打开文件对话框便是典型的模式对话框,在你选择好要打开的文件按下确定后,或者取消打开文件操作后,才可以在同一应用程序进行其他操作。而常见的查找和替换对话框便是无模式对话框的典型,在该对话框打开的同时,我们还可以进行其他工作。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)对话框属于一种资源,VC的资源编辑器可以帮助我们创建和编辑对话框,这个对话框编辑器有点类似VB的编辑器界面了,大多数的常用控件都在控件工具条中列出,我们可以很容易的画出对话框的外观样子,不用象SDK时控件也全部由代码创建。书上给出了建立模式对话框的步骤,希望大家记住它。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)1、用对话框编辑器创建包含各种资源和控件的对话框资源。对话框编辑器会自动更新项目的资源文件。
2、利用Class Wizard来创建CDialog的派生类,并将它和第一步创建的资源相连接。Class Wizard会再项目中自动加入相应的代码和头文件。
3、利用Class Wizard向对话框类中加入数据成员、交换函数和确认函数。
4、利用Class Wizard对对话框中的按钮和其它可以产生事件的控件加入相应的消息控制函数。
5、对一些特殊的控件初始化函数(如OnInitDialog)及消息控制函数进行编辑。当用户关闭对话框时,别忘了调用CDialog的虚成员函数OnOK。OnOK是以默认方式调用的。
6、对视图类代码进行编辑,以便对话框被激活。在所编写的代码中首先应该包含对对话框类构造函数的调用,然后再调用DoModel对话框类成员函数,只有当用户退出对话框时,DoModel才返回。
书上还举了一个例子,这个例子包含了各种类型的控件,不过好象有一处错误(在LANG组合框处)。不过大家最好照书上的步骤完成这个例子,它对于掌握控件和对话框很有帮助,雷神在这里不准备用书上的例子,而是自己写一个有点意思的小程序--“体育彩票选号器” 。
程序的目的:
我经常购买北京的体育彩票,虽然没有中过超过50元的奖,可还是兴趣盎然,只当作是支持体育事业了。我从不费神进行一些概率分析之类的工作,一般都是机选,为了演示对话框的操作,写一个程序实现北京电脑体育彩票36选7的机选功能。
程序运行效果是:
当按下选号键后,由计算机随机选出7个0-36的号码,并显示在对话框中的7个EDIT控件中。
设计思路:
1、为了简单选择"Dialog Base",省去了上面说的第6步。
2、随机数的产生,这是游戏编程的关键,雷神不用细说大家也都明白。用VC产生随机数有两个函数,一个是Rand一个是Srand,我的用法是这样的,先调用srand函数,如srand( (unsigned)time( NULL ) ),这样可以每次产生的随机数序列不同。因为各种编程语言返回的随机数(确切地说是伪随机数)实际上都是根据递推公式计算的一组数值,当序列足够长,这组数值近似满足均匀分布。如果计算伪随机序列的初始数值(称为种子)相同,则计算出来的伪随机序列就是完全相同的(这便是为什么单独使用Rand产生的随机数是一样的原因)。这个特性被有的软件利用于加密和解密。加密时,可以用某个种子数生成一个伪随机序列并对数据进行处理;解密时,再利用种子数生成一个伪随机序列并对加密数据进行还原。这样,对于不知道种子数的人要想解密就需要多费些事了。当然,这种完全相同的序列对于你来说是非常糟糕的。要解决这个问题,需要在每次产生随机序列前,先指定不同的种子,这样计算出来的随机序列就不会完全相同了。你可以在调用rand()函数之前调用srand( (unsigned)time( NULL )),这样以time函数值(即当前时间)作为种子数,因为两次调用rand函数的时间通常是不同的,这样就可以保证随机性了。你也可以使用srand函 数来人为指定种子数。Windows 9x/NT的 游 戏FreeCell就允许用户指定种子数,这样用户如果一次游戏没有成功,下次还可以以同样的发牌结果再玩一次。
3、获得1-36号码的算法:因为我们通过随机函数获得的随机数是一个unsigned int,我们需要进行处理才能得到我们想要的数,在本例是1-36,我的算法是用得到的随机数除36取余再加1,则得到的肯定是1-36范围内的整数。
4、不重复:彩票中的7个数是互不相同的数字,因此还需要加一个判断,新得到的随机数是否有效。
5、排序:得到7个号码后需要对它们按大小排序,这里用的是一种常见的排序法,比较相临的两个数,如果后面的元素大于前面的,就交换位置。
好了,让我们开始吧。
1)新建一个“MFC AppWizard(EXE)”程序GUESS,在选择模式时,选择基于“Dialog”模式,其它选项缺省;
2)将新建的对话框上缺省的控件全部删去(一个OK按钮,一个CANCEL按钮),然后添加一个静态文本控件、7个Edit控件和1个Button控件,右击Button控件选择Properties选项,将Caption属性设为“选号”,同样方法将静态文本控件的Caption属性设定为“电脑体育彩票选号:”;
3)右击任一Edit控件,在出现的菜单中选择“ClassWizard”;在“ClassWizard”中为7个Edit控件一一绑定Int型的变量如下:
Control Ids Type Member
IDC_BUTTON1
IDC_EDIT1 int m_num1
IDC_EDIT2 int m_num2
IDC_EDIT3 int m_num3
IDC_EDIT4 int m_num4
IDC_EDIT5 int m_num5
IDC_EDIT6 int m_num6
IDC_EDIT7 int m_num7
4)在“ClassWizard”中为Button控件添加一个处理过程,选择“Message Maps”选项卡,确定Object IDs是IDC_BUTTON1,双击Messages中的BN_CLICKED,则“ClassWizard”会自动添加一个OnButton1() 函数。
5)编辑CGuessDlg::OnButton1() ,添加以下代码
void CGuessDlg::OnButton1()
{
int temp,pnum[35],num[7]; //临时变量,临时数组
for(int i=0;i35;i++) //共有36个数组元素
pnum[i]=i+1;
//***选号***//
for(i=0;i7;i++)
{
srand( (unsigned)time( NULL ) );
temp=rand();
temp=temp%36+1; //得到一个1-36的数
while(pnum[temp]==0)//如果此元素以被选过则重选
{
srand( (unsigned)time( NULL ) );
temp=rand();
temp=temp%36+1;
}
num[i]=temp; //选定一个号码
pnum[temp]=0; //给该元素置0,表示已被选过,如再有视为无效。
}
//***排序***//
for(int chance=1;chance7;chance++)
{
int position=chance; //元素排序用到的游标
for(i=0;i7;i++){
if(num[position]num[i]) //如果后面的元素大于前面的,就交换位置
{
temp=num[position];
num[position]=num[i];
num[i]=temp;
}
}
}
//***显示***//
m_num1=num[0];
m_num2=num[1];
m_num3=num[2];
m_num4=num[3];
m_num5=num[4];
m_num6=num[5];
m_num7=num[6];
UpdateData(FALSE); //通过变量刷新Edit控件的显示
}
//********************************************************************************
/*说明:CWnd::UpdateData()
UpdateData()的原型如下:
BOOL UpdateData( BOOL bSaveAndValidate = TRUE );
UpdateData()是这样工作的,如果调用UpdateData时传给它的参数是FLASE,那么通过DoDataExchange、DDX_(交换)和DDV_(确认)函数会将数据成员中的值传递给对话框中的控件;反之,如果调用UpdateData时传给它的参数是TRUE,那么通过函数会将对话框的控件传递给数据成员。
本例中DoDataExchange函数在CGuessDlg类中被重载,在代码中是下面这样的:
void CGuessDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CGuessDlg)
DDX_Text(pDX, IDC_EDIT1, m_num1);
DDX_Text(pDX, IDC_EDIT2, m_num2);
DDX_Text(pDX, IDC_EDIT3, m_num3);
DDX_Text(pDX, IDC_EDIT4, m_num4);
DDX_Text(pDX, IDC_EDIT5, m_num5);
DDX_Text(pDX, IDC_EDIT6, m_num6);
DDX_Text(pDX, IDC_EDIT7, m_num7);
/